Springboot单体架构搭建学习:从入门到实践
本文将指导你学习如何使用Spring Boot搭建单体架构,从快速搭建第一个Spring Boot项目开始,详细介绍如何构建基本的Spring Boot项目、实现服务拆分与管理,并最终部署到服务器。Spring Boot单体架构搭建学习涵盖了从基础到高级的各个方面,帮助开发者快速掌握这一技能,让你能够快速构建并部署稳定可靠的单体应用。
Spring Boot简介什么是Spring Boot
Spring Boot 是Spring框架的一个子项目,旨在简化Spring应用的初始搭建及开发过程。它通过约定优于配置的方式,帮助开发者快速搭建Spring应用。Spring Boot的核心目标是简化Spring应用的开发,并且提供一套完整的默认配置,使得开发人员可以快速上手,专注于业务逻辑。
Spring Boot通过提供一系列默认配置,使得开发人员能够快速地创建独立的、生产级别的基于Spring的应用程序,无需大量的XML配置。它还支持嵌入式的Web服务器(如Tomcat、Jetty),可以将应用打包为单一的可执行的jar或者war文件,简化部署过程。
Spring Boot的优势和应用场景
优势
- 快速启动:通过默认配置,开发者可以快速启动并运行应用,减少配置时间。
- 无XML配置:尽可能地减少XML配置文件的使用,采用约定优于配置的模式,使得配置更加简洁。
- 自动配置:Spring Boot可以通过自动配置来减少配置文件的工作量,使得开发人员专注于业务逻辑。
- 嵌入式Web服务器:内置了Tomcat、Jetty等Web服务器,可以将应用打包为可执行的jar或war文件,简化部署过程。
- 模块化开发:提供各种starter依赖,使得开发人员可以快速地引入需要的功能模块,加快开发速度。
- 监控与日志管理:提供了Actuator(监控)和Logback(日志)等模块,便于监控应用状态和管理日志。
- 外部化配置:支持从外部属性文件或环境变量加载配置,提高应用的灵活性和可维护性。
应用场景
Spring Boot适用于各种类型的Java应用开发,特别是以下场景:
- Web应用:快速开发基于Web的应用,可以是RESTful服务、静态页面展示等。
- 微服务应用:虽然Spring Boot可以用于微服务,但更常见的是作为单体应用的基础架构,提供稳定可靠的服务。
- 独立应用:可以将应用打包为可执行的jar文件,独立启动运行,无需外部依赖。
- 快速原型开发:对于快速原型开发,Spring Boot提供了快速配置的功能,可以很快地搭建一个原型系统。
创建Spring Boot项目
- 安装Spring Boot CLI:可以通过Maven或Gradle构建工具来安装Spring Boot CLI,或者使用IDE工具(如Spring Tool Suite、IntelliJ IDEA等)来创建Spring Boot项目。
- 使用Spring Boot CLI创建项目:
spring init --dependencies=web my-first-spring-boot-app cd my-first-spring-boot-app mvn spring-boot:run
- 使用IDE创建项目:使用Spring Initializr插件来创建一个新的Spring Boot项目,选择所需的依赖(如Web、Thymeleaf等),然后直接运行项目。
添加依赖和配置文件
-
pom.xml:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
- application.properties:
server.port=8080 spring.application.name=my-first-spring-boot-app
项目结构
- src/main/java:存放Java源代码,包括主类和业务逻辑类。
- src/main/resources:存放资源文件,如配置文件、静态文件以及模板文件。
- src/test/java:存放测试代码。
- pom.xml:Maven构建文件,包含项目依赖和构建配置。
示例代码
主类(Application.java
):
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
配置文件(application.properties
):
server.port=8080
spring.application.name=my-first-spring-boot-app
构建基本的Spring Boot项目
创建项目
- 使用Spring Initializr创建项目:选择Web依赖,创建一个新的项目。
- 初始化项目:
- 创建一个新的Spring Boot项目,选择Web依赖。
- 初始化项目后,运行项目以确保一切正常。
添加依赖和配置文件
-
pom.xml:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
- application.properties:
server.port=8080 spring.application.name=my-basic-spring-boot-app
实现基本的RESTful服务
-
创建控制器:
package com.example.demo.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HomeController { @GetMapping("/") public String home() { return "Hello, World!"; } }
- 测试服务:启动应用后,访问
http://localhost:8080/
,应显示“Hello, World!”。
什么是单体架构
单体架构(Monolithic Architecture)是一种传统的软件架构模式,将应用的所有功能模块(如用户管理、订单处理、产品展示等)都打包到一个单一的可执行文件中。在这种架构模式下,所有的业务逻辑都是紧密耦合在一起的,通常运行在同一个进程中,共享一个数据库。
单体架构的特点包括:
- 单一代码库:所有功能模块的代码集中在一个代码库中,易于管理和维护。
- 部署简单:整个应用作为一个整体部署,简化了部署流程。
- 易于监控:整个应用作为一个单独的进程运行,监控和调试相对简单。
- 灵活性较低:修改一处代码可能影响到其他模块,增加了开发的复杂性。
单体架构的优点与缺点
优点
- 开发简单:由于所有功能模块都在同一代码库中,开发简单直接。
- 部署方便:整个应用作为一个独立单元部署,简化了部署流程。
- 易于监控:单一进程运行,监控和调试相对简单。
- 易于调试:开发人员可以在同一个代码库中进行调试,不涉及复杂的模块间通信。
缺点
- 扩展性差:整个应用作为一个单一单元运行,扩展性差,不容易水平扩展。
- 维护成本高:代码紧密耦合,修改一处代码可能影响到其他模块。
- 部署复杂:当应用规模变大时,部署和升级变得更加复杂。
- 故障影响范围大:某个模块出现问题,可能导致整个应用不可用。
- 技术栈单一:使用单一的技术栈开发,限制了技术多样性。
单体架构适用场景
单体架构适用于以下场景:
- 小型应用:对于一些小型应用,单体架构可以快速搭建,开发和维护成本较低。
- 早期项目:对于初创项目或早期项目,单体架构可以帮助团队快速启动,减少复杂性。
- 单点服务:如果应用只需要提供有限的服务,单体架构可以很好地满足需求。
- 技术栈单一:如果团队熟悉单一的技术栈,可以高效地使用单体架构进行开发。
实现基本的服务拆分
-
创建新的Java类:
package com.example.demo.service; public class ProductService { public String getProductDetails() { return "Product details"; } }
-
注入服务到控制器:
package com.example.demo.controller; import com.example.demo.service.ProductService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HomeController { @Autowired private ProductService productService; @GetMapping("/products") public String products() { return productService.getProductDetails(); } }
使用Spring Boot管理模块
-
创建新的Java类:
package com.example.demo.module; import org.springframework.context.annotation.Configuration; @Configuration public class ModuleConfig { // 配置模块相关的bean }
-
注入模块配置到控制器:
package com.example.demo.controller; import com.example.demo.module.ModuleConfig; import com.example.demo.service.ProductService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HomeController { @Autowired private ModuleConfig moduleConfig; @Autowired private ProductService productService; @GetMapping("/products") public String products() { return productService.getProductDetails(); } }
数据库设计与连接配置
- 设计数据库:根据应用需求设计数据库表结构。
-
配置数据库连接:
spring.datasource.url=jdbc:mysql://localhost:3306/mydb spring.datasource.username=root spring.datasource.password=root spring.jpa.hibernate.ddl-auto=update
-
使用JPA或MyBatis等持久化框架:使用Spring Data JPA或MyBatis等框架进行数据库操作。
-
创建实体类:
package com.example.demo.entity; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity public class Product { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String name; private double price; // getters and setters }
-
创建Repository接口:
package com.example.demo.repository; import com.example.demo.entity.Product; import org.springframework.data.jpa.repository.JpaRepository; public interface ProductRepository extends JpaRepository<Product, Long> { }
-
使用Repository接口:
package com.example.demo.service; import com.example.demo.entity.Product; import com.example.demo.repository.ProductRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class ProductService { @Autowired private ProductRepository productRepository; public List<Product> getAllProducts() { return productRepository.findAll(); } }
单元测试与集成测试
-
单元测试:
package com.example.demo.service; import com.example.demo.entity.Product; import com.example.demo.repository.ProductRepository; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import static org.mockito.Mockito.when; import static org.junit.jupiter.api.Assertions.assertEquals; public class ProductServiceTest { @Mock private ProductRepository productRepository; @InjectMocks private ProductService productService; @Test public void testGetAllProducts() { MockitoAnnotations.initMocks(this); Product product1 = new Product(); product1.setName("Product 1"); product1.setPrice(10.0); Product product2 = new Product(); product2.setName("Product 2"); product2.setPrice(20.0); when(productRepository.findAll()).thenReturn(List.of(product1, product2)); List<Product> products = productService.getAllProducts(); assertEquals(2, products.size()); assertEquals("Product 1", products.get(0).getName()); assertEquals(10.0, products.get(0).getPrice()); } }
-
集成测试:
package com.example.demo.controller; import com.example.demo.entity.Product; import com.example.demo.repository.ProductRepository; import com.example.demo.service.ProductService; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; import java.util.Arrays; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @ExtendWith(SpringExtension.class) @WebMvcTest public class HomeControllerTest { @Autowired private MockMvc mockMvc; @MockBean private ProductService productService; @Test public void shouldReturnProductList() throws Exception { Product product1 = new Product(); product1.setName("Product 1"); product1.setPrice(10.0); Product product2 = new Product(); product2.setName("Product 2"); product2.setPrice(20.0); when(productService.getAllProducts()).thenReturn(Arrays.asList(product1, product2)); mockMvc.perform(get("/products")) .andExpect(status().isOk()) .andExpect(content().string("[\"Product 1\", \"Product 2\"]")); } }
部署与运行Spring Boot应用
-
打包应用:
mvn clean package
-
运行jar包:
java -jar target/my-spring-boot-app.jar
- 部署到服务器:
scp target/my-spring-boot-app.jar user@server:/path/to/deploy/ ssh user@server java -jar /path/to/deploy/my-spring-boot-app.jar
配置环境变量与日志管理
-
配置环境变量:
spring.profiles.active=dev
-
在
application-dev.properties
中定义环境变量值:spring.datasource.url=jdbc:mysql://localhost:3306/db_dev
-
配置日志框架:
logging.level.root=INFO logging.file.path=/path/to/log
- 使用Spring Boot Actuator:
management.endpoints.web.exposure.include=* management.endpoint.health.show-details=always
构建一个简单的电商应用
需求
构建一个简单的电商应用,包含用户注册、登录、商品浏览等功能。
构建项目
- 创建新的Spring Boot项目:选择Web依赖。
- 初始化项目:
- 创建新的Spring Boot项目,选择Web依赖。
- 初始化项目后,运行项目以确保一切正常。
实现用户注册与登录功能
-
创建用户实体类:
package com.example.demo.entity; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String username; private String password; // getters and setters }
-
创建用户Repository接口:
package com.example.demo.repository; import com.example.demo.entity.User; import org.springframework.data.jpa.repository.JpaRepository; public interface UserRepository extends JpaRepository<User, Long> { }
-
创建用户Service类:
package com.example.demo.service; import com.example.demo.entity.User; import com.example.demo.repository.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Optional; @Service public class UserService { @Autowired private UserRepository userRepository; public Optional<User> findByUsername(String username) { return userRepository.findByUsername(username); } public User save(User user) { return userRepository.save(user); } }
-
创建用户Controller类:
package com.example.demo.controller; import com.example.demo.entity.User; import com.example.demo.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @RestController public class UserController { @Autowired private UserService userService; @PostMapping("/users") public User registerUser(@RequestBody User user) { return userService.save(user); } @GetMapping("/users/{username}") public User getUser(@PathVariable String username) { return userService.findByUsername(username) .orElseThrow(() -> new RuntimeException("User not found")); } }
实现商品浏览功能
-
创建商品实体类:
package com.example.demo.entity; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity public class Product { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String name; private double price; // getters and setters }
-
创建商品Repository接口:
package com.example.demo.repository; import com.example.demo.entity.Product; import org.springframework.data.jpa.repository.JpaRepository; public interface ProductRepository extends JpaRepository<Product, Long> { }
-
创建商品Service类:
package com.example.demo.service; import com.example.demo.entity.Product; import com.example.demo.repository.ProductRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class ProductService { @Autowired private ProductRepository productRepository; public List<Product> getAllProducts() { return productRepository.findAll(); } }
-
创建商品Controller类:
package com.example.demo.controller; import com.example.demo.entity.Product; import com.example.demo.service.ProductService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class ProductController { @Autowired private ProductService productService; @GetMapping("/products") public List<Product> getAllProducts() { return productService.getAllProducts(); } }
部署到本地或云服务器
-
打包应用:
mvn clean package
-
运行jar包:
java -jar target/my-spring-boot-app.jar
- 部署到云服务器:
scp target/my-spring-boot-app.jar user@server:/path/to/deploy/ ssh user@server java -jar /path/to/deploy/my-spring-boot-app.jar
共同学习,写下你的评论
评论加载中...
作者其他优质文章