Web 后端开发

难度等级:⭐⭐⭐ 前置知识:编程语言基础 后续衔接:微服务架构、数据存储

学习路径


一、.NET Web 开发

1.1 ASP.NET Core 基础

ASP.NET Core 是微软推出的跨平台、高性能 Web 框架,采用模块化设计,运行于 .NET 运行时之上。其核心架构围绕中间件管道依赖注入配置系统三大支柱展开。

中间件管道是 ASP.NET Core 请求处理的核心机制。每个中间件组件负责处理 HTTP 请求和响应,它们按注册顺序串联成管道。请求从第一个中间件流入,依次传递,响应则反向流出。中间件通过 app.Use() 注册,短路中间件(如 app.Run())会终止管道。典型管道顺序为:异常处理 → HTTPS 重定向 → 静态文件 → 路由 → 认证 → 授权 → 端点。理解管道顺序至关重要,错误的顺序会导致认证在授权之前未执行等问题。

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

// 中间件管道(顺序重要)
app.UseExceptionHandler("/error");
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();

依赖注入(DI)是 ASP.NET Core 的一等公民。框架内置轻量级 DI 容器,支持三种生命周期:Transient(每次请求创建新实例)、Scoped(同一请求内共享)、Singleton(应用生命周期内唯一)。服务在 Program.cs 中注册,通过构造函数注入到控制器。推荐优先使用 Scoped 注册数据库上下文等有状态服务,避免 Singleton 持有可变状态引发的线程安全问题。

配置系统采用 IConfiguration 抽象,支持多数据源叠加:appsettings.jsonappsettings.{Environment}.json → 环境变量 → 命令行参数 → 用户机密(开发环境)。配置值通过键路径访问(如 Configuration["ConnectionStrings:Default"]),也可通过 IOptions<T> 强类型绑定,实现配置类的集中管理。

// 强类型配置
builder.Services.Configure<JwtSettings>(
    builder.Configuration.GetSection("JwtSettings"));

// 在类中使用
public class AuthService(IOptions<JwtSettings> options)
{
    private readonly JwtSettings _settings = options.Value;
}

路由系统支持传统路由和端点路由两种模式。端点路由(推荐)将路由匹配与请求处理分离,允许中间件在路由决策后介入。属性路由通过 [Route][HttpGet] 等注解定义,约定路由通过 MapControllerRoute 配置。路由约束(如 {id:int})和路由值模型绑定是构建 RESTful API 的基础。

1.2 Web API 设计

RESTful API 设计是后端开发的核心技能。ASP.NET Core 提供了完整的 Web API 构建能力,涵盖控制器、模型验证、响应格式化、版本管理等环节。

RESTful 设计原则强调资源导向、无状态通信、统一接口。资源通过 URI 标识(如 /api/users/123),HTTP 方法表达操作语义(GET 查询、POST 创建、PUT 全量更新、PATCH 局部更新、DELETE 删除)。状态码准确反映操作结果:200 成功、201 创建成功、204 无内容、400 请求错误、401 未认证、403 无权限、404 未找到、500 服务器错误。避免在 GET 请求中修改资源状态,确保接口的幂等性和安全性。

控制器是 API 端点的载体,继承 ControllerBase(非 Controller,后者包含视图支持)。使用 [ApiController] 特性可启用自动模型验证、多部分表单绑定推断、绑定源参数推断等增强行为。推荐将控制器保持轻薄,仅负责请求参数接收、服务调用和响应返回,业务逻辑下沉到服务层。

[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
    private readonly IUserService _userService;

    public UsersController(IUserService userService)
    {
        _userService = userService;
    }

    [HttpGet("{id}")]
    public async Task<ActionResult<UserDto>> GetUser(int id)
    {
        var user = await _userService.GetByIdAsync(id);
        if (user == null)
            return NotFound();
        return Ok(user);
    }

    [HttpPost]
    public async Task<ActionResult<UserDto>> CreateUser(CreateUserRequest request)
    {
        var user = await _userService.CreateAsync(request);
        return CreatedAtAction(nameof(GetUser), new { id = user.Id }, user);
    }
}

模型验证通过 Data Annotations 实现,[Required][StringLength][Range][EmailAddress] 等特性标注在 DTO 属性上。[ApiController] 会自动在动作执行前检查 ModelState.IsValid,验证失败时返回 400 响应。对于复杂验证逻辑,可实现 IValidatableObject 接口或使用 FluentValidation 库,后者支持链式语法和异步验证,更适合企业级项目。

public class CreateUserRequest
{
    [Required]
    [StringLength(50, MinimumLength = 2)]
    public string Name { get; set; }

    [Required]
    [EmailAddress]
    public string Email { get; set; }

    [Range(18, 120)]
    public int Age { get; set; }
}

响应格式化通过内容协商实现,客户端通过 Accept 头指定期望格式,服务端通过 OutputFormatter 匹配。默认支持 JSON 和 XML,推荐仅启用 JSON 以减少攻击面。全局异常处理通过中间件实现,捕获未处理异常后返回统一的错误响应格式,避免泄露堆栈信息。

1.3 Entity Framework Core

Entity Framework Core(EF Core)是 .NET 生态的官方 ORM 框架,支持 Code First、Database First 和 Model First 三种开发模式,其中 Code First 最为常用。

Code First 模式通过 C# 实体类定义数据模型,利用 Fluent API 或 Data Annotations 配置映射关系。数据库上下文 DbContext 是 EF Core 的核心类,管理实体集合和数据库连接。DbSet<T> 表示数据库表的集合,支持 LINQ 查询。迁移(Migration)机制用于管理数据库架构变更,通过 dotnet ef migrations add 生成迁移文件,dotnet ef database update 应用到数据库。迁移文件包含 UpDown 方法,支持正向升级和回滚。

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options)
        : base(options) { }

    public DbSet<User> Users { get; set; }
    public DbSet<Order> Orders { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>(entity =>
        {
            entity.HasKey(e => e.Id);
            entity.Property(e => e.Email).IsRequired().HasMaxLength(100);
            entity.HasIndex(e => e.Email).IsUnique();
            entity.HasMany(e => e.Orders)
                  .WithOne(e => e.User)
                  .HasForeignKey(e => e.UserId);
        });
    }
}

LINQ 查询是 EF Core 的数据访问语言。WhereSelectOrderByIncludeThenInclude 等方法构建查询表达式树,最终翻译为 SQL 执行。Include 用于加载关联实体(eager loading),避免 N+1 查询问题。AsNoTracking() 用于只读查询,跳过变更跟踪以提升性能。Select 投影仅查询需要的字段,减少数据传输量。

// 高效查询示例
var users = await _context.Users
    .AsNoTracking()
    .Where(u => u.IsActive && u.CreatedAt > DateTime.UtcNow.AddDays(-30))
    .Select(u => new { u.Id, u.Name, u.Email })
    .OrderByDescending(u => u.Id)
    .Skip(0)
    .Take(20)
    .ToListAsync();

性能优化是 EF Core 实战的关键。常见问题包括:N+1 查询(通过 Include 或显式加载解决)、变更跟踪开销(只读查询使用 AsNoTracking)、内存中数据膨胀(使用 Select 投影)、批量操作性能(使用 AddRange/ExecuteUpdateAsync 而非循环 Add)。EF Core 7+ 引入了 ExecuteUpdateAsyncExecuteDeleteAsync 用于批量更新和删除,直接在数据库执行而不加载实体到内存。对于超高并发场景,可考虑 Dapper 等轻量级 ORM 作为补充。

// EF Core 7+ 批量更新
await _context.Users
    .Where(u => u.LastLoginAt < DateTime.UtcNow.AddYears(-1))
    .ExecuteUpdateAsync(u => u.SetProperty(x => x.IsActive, false));

二、Java / Spring Boot 开发

2.1 Spring 核心原理

Spring 框架是 Java 生态中最具影响力的企业级开发框架,其核心是 IoC(控制反转)容器AOP(面向切面编程) 两大机制。

IoC 容器负责管理对象的生命周期和依赖关系。传统开发中,对象自行创建依赖(new 关键字),导致紧耦合。IoC 将依赖创建和注入的责任交给容器,对象只需声明依赖,容器在运行时自动注入。Spring 通过 BeanFactoryApplicationContext 实现 IoC,前者是基础容器,后者提供国际化、事件传播等企业级功能。Bean 是容器管理的对象,通过 XML、注解或 Java Config 定义。推荐使用 @Configuration + @Bean@Component 系列注解的 Java Config 方式,类型安全且易于重构。

@Configuration
public class AppConfig {
    @Bean
    public DataSource dataSource() {
        return new HikariDataSource();
    }

    @Bean
    public UserService userService(DataSource dataSource) {
        return new UserServiceImpl(dataSource);
    }
}

Bean 生命周期包含多个阶段:实例化 → 属性注入 → 初始化前(BeanPostProcessor.postProcessBeforeInitialization)→ 初始化(@PostConstructInitializingBean.afterPropertiesSet、自定义 init-method)→ 初始化后(BeanPostProcessor.postProcessAfterInitialization)→ 使用 → 销毁(@PreDestroyDisposableBean.destroy)。理解生命周期对于编写自定义 Bean 处理器和代理至关重要。

AOP 切面编程将横切关注点(日志、事务、安全)与业务逻辑分离。核心概念包括:切面(Aspect,横切逻辑的模块化)、连接点(JoinPoint,程序执行点,如方法调用)、通知(Advice,在连接点执行的动作,分 Before/After/AfterReturning/AfterThrowing/Around)、切点(Pointcut,匹配连接点的表达式)。Spring AOP 基于动态代理实现,默认使用 JDK 动态代理(面向接口)或 CGLIB(面向类)。@Aspect 注解定义切面,@Pointcut 定义切点表达式,@Before/@After 等定义通知。

@Aspect
@Component
public class LoggingAspect {
    @Pointcut("execution(* com.example.service..*(..))")
    public void serviceMethods() {}

    @Around("serviceMethods()")
    public Object logExecutionTime(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = pjp.proceed();
        long elapsed = System.currentTimeMillis() - start;
        System.out.println(pjp.getSignature() + " 执行耗时: " + elapsed + "ms");
        return result;
    }
}

2.2 Spring Boot 自动配置

Spring Boot 的核心价值在于约定优于配置,通过自动配置机制极大简化了 Spring 应用的初始搭建和配置工作。

Starter 机制是一组依赖描述符,将常用场景的依赖打包为一个 Starter POM。例如 spring-boot-starter-web 自动引入 Spring MVC、Tomcat、Jackson 等依赖。Starter 命名遵循 spring-boot-starter-{name} 规范,第三方 Starter 使用 {name}-spring-boot-starter。通过 Starter,开发者只需引入一个依赖即可获得完整的场景支持。

自动配置(Auto-Configuration) 是 Spring Boot 的核心魔法。@EnableAutoConfiguration 注解触发 spring.factories(Spring Boot 3.x 改为 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports)中声明的自动配置类。每个自动配置类通过 @Conditional 系列注解判断是否生效,例如 @ConditionalOnClass(类路径存在某类时生效)、@ConditionalOnMissingBean(容器中不存在某 Bean 时生效)、@ConditionalOnProperty(配置属性满足条件时生效)。

// 简化的自动配置类示例
@Configuration
@ConditionalOnClass(DataSource.class)
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public DataSource dataSource(DataSourceProperties properties) {
        HikariDataSource ds = new HikariDataSource();
        ds.setJdbcUrl(properties.getUrl());
        ds.setUsername(properties.getUsername());
        ds.setPassword(properties.getPassword());
        return ds;
    }
}

条件注解的优先级决定了自动配置的覆盖顺序。用户自定义的 @Bean 优先级最高(因为 @ConditionalOnMissingBean 会跳过),其次是 @Configuration 类中的 Bean,最后是自动配置类中的 Bean。这种设计允许开发者通过自定义 Bean 轻松覆盖默认配置。spring-boot-autoconfigure 源码是学习 Spring Boot 设计思想的最佳材料。

外部化配置支持 YAML、Properties、环境变量、命令行参数等多种格式,按优先级叠加:命令行参数 > Java 系统属性 > 操作系统环境变量 > application-{profile}.yml > application.yml@Value 注解注入单个属性值,@ConfigurationProperties 批量绑定到 POJO,后者支持 JSR-303 校验和元数据提示,是推荐做法。

@ConfigurationProperties(prefix = "app.security")
@Validated
public class SecurityProperties {
    @NotBlank
    private String jwtSecret;
    private long tokenExpiration = 3600;
    private List<String> allowedOrigins = List.of("*");
}

2.3 Spring MVC

Spring MVC 是 Spring 的 Web 模块,基于前端控制器模式构建,所有请求统一经过 DispatcherServlet 分发处理。

DispatcherServlet 是 Spring MVC 的核心中枢,负责请求的统一分发。处理流程为:接收请求 → HandlerMapping 查找匹配的处理器 → HandlerAdapter 执行处理器 → 处理器返回 ModelAndViewViewResolver 解析视图 → 渲染响应。在 RESTful API 场景中,处理器直接返回数据对象(标注 @RestController),跳过视图解析环节,由 HttpMessageConverter 将对象序列化为 JSON。

拦截器(Interceptor) 在请求到达控制器前后执行,实现横切逻辑。实现 HandlerInterceptor 接口,重写 preHandle(控制器前)、postHandle(控制器后、视图渲染前)、afterCompletion(请求完成后)方法。拦截器适用于日志记录、性能监控、权限校验等场景。与 Filter 的区别在于:Filter 属于 Servlet 规范,在 DispatcherServlet 之前执行;拦截器属于 Spring MVC,在 DispatcherServlet 内部执行,可访问 Spring 容器中的 Bean。

@Component
public class AuthInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) {
        String token = request.getHeader("Authorization");
        if (token == null || !token.startsWith("Bearer ")) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }
        return true;
    }
}

异常处理通过 @ControllerAdvice + @ExceptionHandler 实现全局统一处理。标注 @ControllerAdvice 的类可拦截所有控制器抛出的异常,@ExceptionHandler 方法针对特定异常类型返回自定义响应。结合 @ResponseStatus 可设置 HTTP 状态码。推荐定义统一的错误响应结构(包含错误码、消息、详情),便于前端统一处理。

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ErrorResponse handleNotFound(ResourceNotFoundException ex) {
        return new ErrorResponse("NOT_FOUND", ex.getMessage());
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ErrorResponse handleValidation(MethodArgumentNotValidException ex) {
        String message = ex.getBindingResult().getFieldErrors().stream()
            .map(FieldError::getDefaultMessage)
            .collect(Collectors.joining(", "));
        return new ErrorResponse("VALIDATION_ERROR", message);
    }
}

参数绑定将 HTTP 请求数据映射到控制器方法参数。@RequestParam 绑定查询参数,@PathVariable 绑定路径变量,@RequestBody 绑定请求体(自动反序列化),@RequestHeader 绑定请求头。@Valid@Validated 触发 JSR-303 校验,校验失败抛出 MethodArgumentNotValidException。Spring Boot 3.x 从 javax.validation 迁移到 jakarta.validation,注意包名变更。

2.4 Spring Data JPA

Spring Data JPA 是 Spring 对 JPA(Java Persistence API)的抽象封装,通过约定优于配置的理念极大简化了数据访问层的开发。

Repository 抽象是 Spring Data 的核心。定义接口继承 JpaRepository<T, ID> 即可自动获得 CRUD、分页、排序等基础方法,无需编写实现类。Spring 在运行时通过动态代理生成实现。CrudRepository 提供基础 CRUD,PagingAndSortingRepository 增加分页和排序,JpaRepository 在此基础上增加批量操作和 JPA 特有功能。

public interface UserRepository extends JpaRepository<User, Long> {
    // 方法名派生查询
    Optional<User> findByEmail(String email);
    List<User> findByStatusAndCreatedAtAfter(String status, LocalDateTime date);
    boolean existsByUsername(String username);

    // JPQL 查询
    @Query("SELECT u FROM User u WHERE u.email LIKE %:keyword%")
    List<User> searchByEmail(@Param("keyword") String keyword);

    // 原生 SQL
    @Query(value = "SELECT * FROM users WHERE status = ?1", nativeQuery = true)
    List<User> findByStatusNative(String status);

    // 更新操作
    @Modifying
    @Query("UPDATE User u SET u.status = :status WHERE u.id = :id")
    int updateStatus(@Param("id") Long id, @Param("status") String status);
}

查询方法派生通过方法名自动解析查询逻辑。findByreadBygetBy 为前缀,后接属性名和关键字(AndOrBetweenLessThanLikeOrderBy 等)。Spring 解析方法名生成对应的 JPQL 查询。这种方式适合简单查询,复杂查询仍需 @Query 注解。

分页与排序通过 PageableSort 参数实现。PageRequest.of(page, size, Sort.by("createdAt").descending()) 构建分页排序对象。返回类型使用 Page<T> 可获取总记录数、总页数等元数据,使用 List<T>Slice<T> 则仅返回当前页数据。

// 分页查询
Page<User> page = userRepository.findAll(
    PageRequest.of(0, 20, Sort.by("createdAt").descending()));

List<User> content = page.getContent();
long totalElements = page.getTotalElements();
int totalPages = page.getTotalPages();

实体关系映射通过 @OneToOne@OneToMany@ManyToOne@ManyToMany 定义。注意懒加载(FetchType.LAZY)与急加载(FetchType.EAGER)的选择,默认 @OneToMany 为懒加载,@ManyToOne 为急加载。懒加载在访问关联属性时触发额外查询,可能导致 N+1 问题。使用 @EntityGraph 或 JPQL JOIN FETCH 可一次性加载关联数据。

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
    private List<Order> orders;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "department_id")
    private Department department;
}

2.5 MyBatis

MyBatis 是半自动 ORM 框架,将 SQL 控制权完全交给开发者,通过 XML 映射文件或注解将 SQL 结果映射到 Java 对象。在复杂查询、性能调优、遗留数据库适配等场景中,MyBatis 比 JPA 更具灵活性。

XML 映射是 MyBatis 的核心用法。每个 Mapper 接口对应一个 XML 文件,namespace 指向接口的全限定名。<select><insert><update><delete> 标签定义 SQL 语句,id 对应接口方法名,resultTyperesultMap 指定结果映射。#{} 是预编译参数占位符(防 SQL 注入),${} 是字符串替换(用于动态表名、列名,需注意注入风险)。

<!-- UserMapper.xml -->
<mapper namespace="com.example.mapper.UserMapper">

    <resultMap id="userResultMap" type="User">
        <id property="id" column="id"/>
        <result property="username" column="username"/>
        <result property="email" column="email"/>
        <association property="department" javaType="Department">
            <id property="id" column="dept_id"/>
            <result property="name" column="dept_name"/>
        </association>
    </resultMap>

    <select id="findById" resultMap="userResultMap">
        SELECT u.*, d.id AS dept_id, d.name AS dept_name
        FROM users u
        LEFT JOIN departments d ON u.department_id = d.id
        WHERE u.id = #{id}
    </select>

    <select id="search" resultMap="userResultMap">
        SELECT * FROM users
        <where>
            <if test="keyword != null">
                AND (username LIKE CONCAT('%', #{keyword}, '%')
                     OR email LIKE CONCAT('%', #{keyword}, '%'))
            </if>
            <if test="status != null">
                AND status = #{status}
            </if>
        </where>
        ORDER BY created_at DESC
        LIMIT #{offset}, #{limit}
    </select>
</mapper>

动态 SQL 是 MyBatis 的亮点。<if> 条件判断、<choose>/<when>/<otherwise> 多分支选择、<foreach> 集合遍历、<where> 智能拼接 WHERE 子句(自动去除多余 AND/OR)、<set> 智能拼接 SET 子句(自动去除多余逗号)、<trim> 自定义前后缀和覆盖。这些标签使 SQL 可根据参数动态生成,避免编写大量重复的 SQL 变体。

插件机制通过实现 Interceptor 接口拦截 MyBatis 内部方法执行。典型应用包括:分页插件(如 PageHelper 拦截 SQL 添加 LIMIT)、SQL 性能监控插件(记录慢查询)、数据权限插件(自动追加 WHERE 条件)。插件通过 @Intercepts@Signature 注解声明拦截点,可拦截 ExecutorParameterHandlerResultSetHandlerStatementHandler 四个核心组件。

@Intercepts({
    @Signature(type = Executor.class, method = "query",
               args = {MappedStatement.class, Object.class,
                       RowBounds.class, ResultHandler.class})
})
public class SqlTimerInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = invocation.proceed();
        long elapsed = System.currentTimeMillis() - start;
        if (elapsed > 1000) {
            log.warn("慢查询: {}ms", elapsed);
        }
        return result;
    }
}

MyBatis-Plus 是 MyBatis 的增强工具,在保持 MyBatis 灵活性的同时提供了类似 Spring Data JPA 的 CRUD 抽象。BaseMapper<T> 提供基础 CRUD,IService<T> 提供业务层封装,Wrappers 提供链式查询构建器。代码生成器可根据数据库表自动生成实体类、Mapper、Service、Controller 代码,大幅提升开发效率。

2.6 Spring Security

Spring Security 是 Spring 生态的认证与授权框架,功能强大但学习曲线较陡。其核心模型围绕认证(Authentication)授权(Authorization)展开。

认证流程基于 AuthenticationManagerAuthenticationProviderUserDetailsService 的链路。AuthenticationManager 是认证入口,委托给 AuthenticationProvider 执行具体认证逻辑。DaoAuthenticationProvider 是最常用的 Provider,通过 UserDetailsService.loadUserByUsername() 加载用户信息,比对密码。认证成功生成包含用户信息和权限的 Authentication 对象,存入 SecurityContextHolder(默认基于 ThreadLocal)。

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.disable())
            .sessionManagement(session ->
                session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/auth/**").permitAll()
                .requestMatchers("/api/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .addFilterBefore(jwtAuthFilter,
                UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

授权模型基于角色(Role)和权限(Authority)。hasRole() 检查角色(自动添加 ROLE_ 前缀),hasAuthority() 检查具体权限,hasAnyRole()/hasAnyAuthority() 检查多个。方法级安全通过 @EnableMethodSecurity 启用,支持 @PreAuthorize(方法执行前校验)、@PostAuthorize(方法执行后校验)、@PreFilter/@PostFilter(集合过滤)。

JWT 集成是无状态认证的常见方案。JWT(JSON Web Token)包含 Header、Payload、Signature 三部分,服务端签发后客户端存储在请求头中。自定义 Filter 拦截请求,提取并验证 Token,构建 Authentication 对象存入 SecurityContext。注意 JWT 无法主动失效,需配合短有效期 + Refresh Token 或 Token 黑名单机制。

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain)
            throws ServletException, IOException {
        String token = extractToken(request);
        if (token != null && jwtUtil.validateToken(token)) {
            String username = jwtUtil.getUsername(token);
            Authentication auth = new UsernamePasswordAuthenticationToken(
                username, null, jwtUtil.getAuthorities(token));
            SecurityContextHolder.getContext().setAuthentication(auth);
        }
        filterChain.doFilter(request, response);
    }
}

OAuth2 是第三方授权的标准协议。Spring Security OAuth2 支持 Authorization Server(颁发 Token)和 Resource Server(验证 Token)两种角色。Resource Server 配置通过 oauth2ResourceServer() 实现,自动验证 JWT 签名并提取权限信息。

2.7 事务管理

事务是保证数据一致性的核心机制。Spring 通过 @Transactional 注解提供声明式事务管理,基于 AOP 代理实现。

@Transactional 工作原理:标注该注解的方法被调用时,Spring 在方法执行前开启事务,正常返回时提交事务,抛出异常时回滚事务。默认仅对 RuntimeExceptionError 回滚,检查型异常(Checked Exception)不回滚,可通过 rollbackFor 属性修改。事务通过 AOP 代理实现,同类内部方法调用不会触发事务(因为绕过了代理),需通过注入自身或 AopContext.currentProxy() 解决。

@Service
public class OrderService {

    @Transactional
    public Order createOrder(OrderRequest request) {
        Order order = orderRepository.save(request.toEntity());
        // 扣减库存
        inventoryService.deduct(request.getItems());
        // 发送通知
        notificationService.send(order);
        return order;
    }

    @Transactional(readOnly = true)
    public List<Order> getOrders(Long userId) {
        return orderRepository.findByUserId(userId);
    }
}

传播行为(Propagation) 定义方法被另一个事务方法调用时的事务行为。REQUIRED(默认):加入现有事务,不存在则新建;REQUIRES_NEW:挂起现有事务,新建独立事务;NESTED:嵌套事务(保存点机制);SUPPORTS:有事务则加入,没有则以非事务执行;NOT_SUPPORTED:以非事务执行,挂起现有事务;NEVER:以非事务执行,有事务则抛异常;MANDATORY:必须存在事务,否则抛异常。REQUIRES_NEW 常用于日志记录等需要独立提交的场景。

隔离级别(Isolation) 控制并发事务的可见性。READ_UNCOMMITTED(读未提交,最低级别,可能脏读)、READ_COMMITTED(读已提交,大多数数据库默认,防止脏读但可能不可重复读)、REPEATABLE_READ(可重复读,MySQL 默认,防止不可重复读但可能幻读)、SERIALIZABLE(串行化,最高级别,完全隔离但性能最差)、DEFAULT(使用数据库默认)。实际开发中通常使用数据库默认级别,配合乐观锁(@Version)处理并发更新冲突。

@Transactional(
    propagation = Propagation.REQUIRES_NEW,
    isolation = Isolation.READ_COMMITTED,
    rollbackFor = Exception.class,
    timeout = 30,
    readOnly = false
)
public void processPayment(PaymentRequest request) {
    // 独立事务,不受外层事务影响
}

事务失效场景:方法非 public、同类内部调用、异常被 try-catch 吞掉、数据库引擎不支持事务(如 MyISAM)。排查事务问题时,可开启 Spring 事务日志(logging.level.org.springframework.transaction=DEBUG)观察事务的开启、提交、回滚过程。


三、Python Web 开发

3.1 FastAPI 框架

FastAPI 是 Python 生态中增长最快的现代 Web 框架,基于 Starlette(ASGI)和 Pydantic 构建,以高性能和自动文档生成著称。

路由与请求处理通过装饰器定义,支持所有 HTTP 方法。路径参数通过花括号声明,查询参数通过函数参数自动推断。FastAPI 利用 Python 类型注解实现自动参数解析和校验,无需额外的验证库。async def 定义异步端点,适合 I/O 密集型操作;普通 def 在线程池中执行,适合 CPU 密集型或阻塞操作。

from fastapi import FastAPI, HTTPException, Query
from pydantic import BaseModel, EmailStr, Field

app = FastAPI(title="用户管理 API", version="1.0.0")

class UserCreate(BaseModel):
    name: str = Field(..., min_length=2, max_length=50)
    email: EmailStr
    age: int = Field(..., ge=18, le=120)

class UserResponse(BaseModel):
    id: int
    name: str
    email: str

@app.post("/users", response_model=UserResponse, status_code=201)
async def create_user(user: UserCreate):
    # 创建用户逻辑
    return UserResponse(id=1, name=user.name, email=user.email)

@app.get("/users/{user_id}", response_model=UserResponse)
async def get_user(user_id: int):
    return UserResponse(id=user_id, name="张三", email="zhangsan@example.com")

@app.get("/search")
async def search_users(
    keyword: str = Query(..., min_length=1),
    page: int = Query(1, ge=1),
    size: int = Query(20, ge=1, le=100)
):
    return {"keyword": keyword, "page": page, "size": size}

Pydantic 模型是 FastAPI 的数据验证核心。继承 BaseModel 定义数据结构,字段类型注解自动触发校验。Field() 提供额外约束(范围、长度、正则表达式)。嵌套模型、泛型模型、模型继承均被支持。response_model 参数控制响应输出,自动过滤未声明的字段(如密码等敏感信息),并执行数据序列化。

依赖注入通过 Depends 实现,是 FastAPI 最强大的特性之一。依赖可以是函数或类,支持嵌套依赖和子依赖。常见用途包括:数据库会话管理、用户认证、权限校验、分页参数提取。依赖的返回值注入到端点参数中,生命周期通过 yield 控制(yield 前为准备阶段,yield 后为清理阶段)。

from fastapi import Depends
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker

# 数据库会话依赖
async def get_db() -> AsyncGenerator[AsyncSession, None]:
    async with async_session() as session:
        try:
            yield session
            await session.commit()
        except Exception:
            await session.rollback()
            raise

# 认证依赖
async def get_current_user(
    token: str = Depends(oauth2_scheme),
    db: AsyncSession = Depends(get_db)
) -> User:
    payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
    user = await db.get(User, payload["sub"])
    if not user:
        raise HTTPException(status_code=401, detail="无效的用户")
    return user

# 端点中使用
@app.get("/users/me", response_model=UserResponse)
async def get_me(current_user: User = Depends(get_current_user)):
    return current_user

异步支持是 FastAPI 的核心优势。基于 ASGI 协议和 asyncio,FastAPI 可原生处理并发连接。async def 端点中应使用异步库(如 httpxmotordatabases),避免阻塞事件循环。对于同步阻塞操作(如传统 ORM),FastAPI 自动在线程池中执行,但会损失部分并发性能。SQLAlchemy 2.0+ 提供了完整的异步支持(AsyncSession),推荐与 FastAPI 配合使用。

自动文档是 FastAPI 的标志性功能。启动后自动在 /docs 提供 Swagger UI,在 /redoc 提供 ReDoc 界面。文档基于 OpenAPI 3.0 规范,包含所有端点、参数、请求体、响应模型的完整描述。可通过 openapi_urldocs_urlredoc_url 参数自定义路径或禁用。文档可直接用于 API 测试,极大提升了前后端协作效率。

3.2 SQLAlchemy ORM

SQLAlchemy 是 Python 生态最成熟的 ORM 框架,2.0 版本引入了统一的异步 API 和更严格的类型支持。

模型定义通过声明式基类实现。SQLAlchemy 2.0 推荐使用 Mapped 类型注解和 mapped_column,替代传统的 Column 声明方式。模型类继承 DeclarativeBase,属性通过类型注解映射到数据库列。关系通过 relationship() 定义,支持懒加载、级联删除、反向引用等配置。

from sqlalchemy import String, Integer, ForeignKey, DateTime
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
from datetime import datetime

Base = DeclarativeBase()

class User(Base):
    __tablename__ = "users"

    id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
    name: Mapped[str] = mapped_column(String(50), nullable=False)
    email: Mapped[str] = mapped_column(String(100), unique=True, nullable=False)
    created_at: Mapped[datetime] = mapped_column(default=datetime.utcnow)

    orders: Mapped[list["Order"]] = relationship(back_populates="user")

class Order(Base):
    __tablename__ = "orders"

    id: Mapped[int] = mapped_column(primary_key=True)
    user_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
    amount: Mapped[float] = mapped_column(nullable=False)

    user: Mapped["User"] = relationship(back_populates="orders")

会话管理通过 Session(同步)或 AsyncSession(异步)实现。会话是 ORM 操作的工作单元,跟踪所有对象的状态变化。session.add() 添加新对象,session.commit() 提交事务,session.rollback() 回滚。异步会话在 FastAPI 中通过依赖注入管理生命周期,确保每个请求使用独立会话并在请求结束时关闭。

# 异步查询示例
async def get_user_orders(session: AsyncSession, user_id: int):
    result = await session.execute(
        select(Order)
        .where(Order.user_id == user_id)
        .order_by(Order.created_at.desc())
        .limit(20)
    )
    return result.scalars().all()

# 关联查询
async def get_user_with_orders(session: AsyncSession, user_id: int):
    result = await session.execute(
        select(User)
        .options(selectinload(User.orders))
        .where(User.id == user_id)
    )
    return result.scalars().first()

查询构建使用 SQLAlchemy 2.0 的 select() 风格,替代旧的 session.query() 风格。select() 构建查询对象,session.execute() 执行。where() 过滤条件,order_by() 排序,limit()/offset() 分页,join() 关联查询。selectinload()joinedload() 控制关联加载策略,前者通过额外 SELECT 加载关联数据(适合一对多),后者通过 JOIN 加载(适合多对一)。

from sqlalchemy import select, func

# 分页查询
async def search_users(
    session: AsyncSession,
    keyword: str,
    page: int = 1,
    size: int = 20
):
    offset = (page - 1) * size
    query = (
        select(User)
        .where(User.name.contains(keyword) | User.email.contains(keyword))
        .order_by(User.created_at.desc())
        .offset(offset)
        .limit(size)
    )
    result = await session.execute(query)
    return result.scalars().all()

# 聚合查询
async def get_order_stats(session: AsyncSession, user_id: int):
    result = await session.execute(
        select(
            func.count(Order.id).label("total"),
            func.sum(Order.amount).label("total_amount"),
            func.avg(Order.amount).label("avg_amount")
        ).where(Order.user_id == user_id)
    )
    return result.one()

Alembic 迁移是 SQLAlchemy 的数据库迁移工具。alembic init 初始化迁移环境,alembic revision --autogenerate -m "描述" 根据模型变更自动生成迁移脚本,alembic upgrade head 应用迁移。迁移文件包含 upgrade()downgrade() 函数,支持正向和回滚操作。

3.3 部署方案

Python Web 应用的部署涉及 ASGI 服务器、进程管理和反向代理三个层次。

Uvicorn 是基于 uvloophttptools 的高性能 ASGI 服务器,是 FastAPI 的推荐运行环境。uvloopasyncio 的高性能事件循环实现,基于 libuv(Node.js 同款)。Uvicorn 支持 HTTP/1.1、HTTP/2、WebSocket,单进程可处理数千并发连接。开发环境直接运行 uvicorn main:app --reload,生产环境需配合进程管理器。

# 开发环境
uvicorn main:app --reload --host 0.0.0.0 --port 8000

# 生产环境(多进程)
gunicorn main:app \
    -w 4 \
    -k uvicorn.workers.UvicornWorker \
    --bind 0.0.0.0:8000 \
    --access-logfile - \
    --error-logfile -

Gunicorn 是 Python 生态最成熟的 WSGI/ASGI 进程管理器。通过 -w 参数指定工作进程数(推荐 2 * CPU核心数 + 1),-k 指定 worker 类型。运行 FastAPI 时使用 uvicorn.workers.UvicornWorker,将每个进程变为异步 ASGI worker。Gunicorn 负责进程管理、优雅重启、日志轮转等运维任务。

Nginx 反向代理 是生产部署的标准配置。Nginx 作为前端代理,负责 SSL 终止、静态文件服务、请求限流、负载均衡。Gunicorn 运行在后端端口,不直接暴露给外部网络。Nginx 配置中设置 proxy_pass 指向 Gunicorn,配置 proxy_set_header 传递真实客户端 IP 和协议信息。

server {
    listen 80;
    server_name api.example.com;

    # 静态文件
    location /static/ {
        alias /app/static/;
        expires 30d;
    }

    # 反向代理
    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 60s;
    }

    # 限流
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
    location /api/ {
        limit_req zone=api burst=20 nodelay;
        proxy_pass http://127.0.0.1:8000;
    }
}

Docker 容器化是现代部署的标准方式。多阶段构建减小镜像体积,非 root 用户运行提升安全性,健康检查确保容器可用性。Docker Compose 编排应用、数据库、缓存等服务。Kubernetes 进一步提供自动扩缩容、服务发现、配置管理等能力。

FROM python:3.12-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY . .
RUN useradd -m appuser && chown -R appuser:appuser /app
USER appuser
EXPOSE 8000
HEALTHCHECK CMD curl -f http://localhost:8000/health || exit 1
CMD ["gunicorn", "main:app", "-w", "4", "-k", "uvicorn.workers.UvicornWorker", "--bind", "0.0.0.0:8000"]

四、跨框架对比

概念 ASP.NET Core Spring Boot FastAPI
依赖注入 内置 DI 容器(Transient/Scoped/Singleton) Spring IoC(singleton/prototype/request/session) Depends(函数/类依赖)
ORM EF Core(LINQ、迁移) JPA/MyBatis(Repository/XML) SQLAlchemy(声明式、Alembic)
中间件 IMiddleware 管道 Filter/Interceptor/HandlerInterceptor Starlette Middleware
配置系统 IConfiguration + IOptions @ConfigurationProperties + @Value Pydantic Settings / env vars
验证 Data Annotations / FluentValidation JSR-303 / Hibernate Validator Pydantic 类型注解
异步支持 async/await(原生) 虚拟线程(Java 21+)/ CompletableFuture async/await(原生 ASGI)
文档生成 Swagger/Swashbuckle SpringDoc OpenAPI 自动生成(OpenAPI 3.0)
事务管理 DbContext 事务 / TransactionScope @Transactional(AOP 代理) 手动 / 依赖注入管理
安全认证 ASP.NET Core Identity / JWT Spring Security(认证链) OAuth2 / JWT 手动集成
部署 Kestrel + Nginx / IIS / Docker Tomcat/Jetty(内嵌) + Nginx Uvicorn + Gunicorn + Nginx
性能 高(基准测试领先) 中(JVM 启动慢,运行时稳定) 高(ASGI + uvloop)
学习曲线 中等 陡峭(概念多) 平缓(Pythonic)

选型建议


五、学习资源推荐

.NET / ASP.NET Core

Java / Spring Boot

Python / FastAPI

通用后端知识