Spring Boot笔记

Spring Boot


🌟 模块一:Spring 纯注解配置 (告别 XML)

本模块详解如何用 5 个核心注解完全替代 applicationContext.xml

1. @Bean ------ 手动注册组件

  • 核心作用:将方法的返回值对象放入 Spring IOC 容器。
  • 等价 XML<bean id="xxx" class="com.xxx.Xxx"/>
  • 关键属性
    • value / name:指定 Bean 在容器中的唯一标识(ID)。若不写,默认为方法名。
  • 使用场景 :第三方包中的类(无法添加 @Component 注解),需要手动配置时。
💻 示例代码
java 复制代码
@Configuration
public class MyDataSourceConfig {

    // 等价于:<bean id="myDruidDataSource" class="com.alibaba.druid.pool.DruidDataSource"/>
    @Bean("myDruidDataSource") 
    public DruidDataSource dataSource() {
        DruidDataSource ds = new DruidDataSource();
        ds.setUrl("jdbc:mysql://localhost:3306/db_test");
        ds.setUsername("root");
        ds.setPassword("123456");
        return ds;
    }
    
    // 默认 ID 为 "userService"
    @Bean 
    public UserService userService() {
        return new UserServiceImpl();
    }
}

2. @PropertySource ------ 加载外部属性文件

  • 核心作用 :加载指定的 .properties 文件到 Spring 环境变量中。
  • 等价 XML<context:property-placeholder location="classpath:db.properties"/>
  • 关键属性
    • value:文件路径,支持数组加载多个文件。
    • encoding:指定编码(如 utf-8),防止中文乱码。
  • 配合使用 :通常与 @Value("${key}") 搭配使用。
💻 示例代码

配置文件 db.properties:

properties 复制代码
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_db
jdbc.user=root
jdbc.password=secret

Java 配置类:

java 复制代码
@Configuration
// 加载单个文件
@PropertySource(value = "classpath:db.properties", encoding = "utf-8")
// 也可以加载多个:@PropertySource({"classpath:a.properties", "classpath:b.properties"})
public class JdbcConfig {

    @Value("${jdbc.driver}")
    private String driver;
    
    @Value("${jdbc.url}")
    private String url;

    @Bean
    public DataSource dataSource() {
        // 使用加载到的属性值
        DriverManagerDataSource ds = new DriverManagerDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        return ds;
    }
}

3. @ComponentScan ------ 组件扫描

  • 核心作用 :指定 Spring 扫描哪些包下的注解(@Component, @Service, @Controller, @Repository)。
  • 等价 XML<context:component-scan base-package="com.hg"/>
  • 关键属性
    • value / basePackages:要扫描的包名数组。
    • excludeFilters:排除某些组件。
    • includeFilters:只包含某些组件。
  • 注意:如果配置类在根包下,有时可以省略,但显式声明更稳妥。
💻 示例代码
java 复制代码
@Configuration
// 扫描 com.hg 及其子包
@ComponentScan("com.hg") 
// 或者排除特定的控制器
// @ComponentScan(value = "com.hg", excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = Controller.class))
public class ScanConfig {
    // Spring 会自动发现 @Service, @Controller 等并注册为 Bean
}

4. @Import ------ 导入配置类

  • 核心作用:导入其他的配置类,实现配置的分模块管理;或者直接导入普通类将其注册为 Bean。
  • 等价 XML<import resource="spring-dao.xml"/>
  • 关键属性
    • value:要导入的类的 Class 对象。
  • 高阶用法
    1. 导入 @Configuration 类:合并配置。
    2. 导入普通类:Spring 会直接将该类注册为 Bean,ID 为类名首字母小写。
    3. 导入 ImportSelectorImportBeanDefinitionRegistrar:实现高级动态注册(如 @EnableXXX 的原理)。
💻 示例代码

子配置类 RedisConfig.java:

java 复制代码
@Configuration
public class RedisConfig {
    @Bean
    public JedisConnectionFactory jedisConnectionFactory() {
        return new JedisConnectionFactory();
    }
}

主配置类 AllConfig.java:

java 复制代码
@Configuration
@ComponentScan("com.hg")
// 导入其他配置类,相当于把 RedisConfig 里的 Bean 也加进来了
@Import({RedisConfig.class, MyDataSourceConfig.class}) 
public class AllConfig {
    // 这里可以直接注入 RedisConfig 中定义的 Bean
}

5. @Configuration ------ 配置类标识

  • 核心作用 :告诉 Spring 这是一个配置类,替代 applicationContext.xml 的地位。
  • 特点
    • 类中通常包含 @Bean 方法。
    • 会被 CGLIB 代理,保证 @Bean 方法调用的单例性(即方法内互相调用不会创建新对象)。
  • 等价物 :整个 applicationContext.xml 文件。
💻 示例代码
java 复制代码
// 必须加这个注解,否则 @Bean 不生效
@Configuration 
@ComponentScan("com.hg")
@PropertySource("classpath:app.properties")
public class SpringMainConfig {
    
    @Bean
    public TransferService transferService() {
        return new TransferServiceImpl();
    }
}

🚀 模块二:Spring Boot 入门

一、Spring Boot 介绍

  • 定义 :Spring + Spring MVC 的快速开发脚手架。不是 对 Spring 功能的增强,而是简化配置
  • 三大特点
    1. 简化 XML:零配置或极少配置。
    2. 简化 Maven:通过 Starter 解决依赖版本冲突。
    3. 内嵌 Tomcat:无需部署 WAR,直接运行 JAR。

二、入门案例实操

1. pom.xml 核心配置
xml 复制代码
<project xmlns="http://maven.apache.org/POM/4.0.0" ...>
    <!-- ① 继承父工程:锁定所有依赖版本 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
        <relativePath/>
    </parent>

    <dependencies>
        <!-- ② 引入 Web 启动器:包含 Spring MVC, Tomcat, Jackson -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
</project>
2. Controller 层代码
java 复制代码
package com.hg.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController // 组合注解:@Controller + @ResponseBody
public class HelloController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello Spring Boot! 欢迎进入快速开发时代 🚀";
    }
}
3. 启动类 (关键!)

⚠️ 包结构要求 :启动类必须在所有业务包(controller, service, mapper)的父级目录,否则默认扫描不到。

java 复制代码
package com.hg; // 【重要】必须是根包

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication // 核心:开启自动配置 + 组件扫描
public class SpringbootHelloworldApp {

    public static void main(String[] args) {
        // 启动应用,返回 ApplicationContext
        SpringApplication.run(SpringbootHelloworldApp.class, args);
        System.out.println("✅ 启动成功!访问 http://localhost:8080/hello");
    }
}

三、Spring Boot 启动器 (Starter)

1. 概念

Starter 是一组便捷的依赖描述符。引入一个 Starter,就等于引入了该功能所需的所有 Jar 包和自动配置类。

2. 命名规范
类型 命名格式 示例 说明
官方 spring-boot-starter-模块名 spring-boot-starter-web Spring 官方提供
第三方 模块名-spring-boot-starter mybatis-spring-boot-starter 第三方组织提供 (如 MyBatis-Plus)
💡 知识补充:常用 Starter
  • spring-boot-starter-data-jpa: JPA 数据访问
  • spring-boot-starter-data-redis: Redis 支持
  • spring-boot-starter-test: 测试支持 (JUnit, Mockito)
  • spring-boot-starter-security: 安全认证

四、配置文件 (Properties vs YML)

1. application.properties
properties 复制代码
# 修改 Tomcat 端口
server.port=8090
# 修改项目上下文路径
server.servlet.context-path=/springboot_helloworld
# 设置日志级别
logging.level.com.hg=debug
2. application.yml (推荐)

语法重点

  • 层级用缩进(空格,不能 Tab)。
  • 键值对用 : (冒号后必须有空格)。
  • 大小写敏感。
yaml 复制代码
server:
  port: 8090
  servlet:
    context-path: /springboot_helloworld

logging:
  level:
    com.hg: debug

五、两种发布方式

1. JAR 方式 (主流 ✅)
  • 原理:内嵌 Tomcat,自包含运行环境。
  • 步骤
    1. 插件配置 (pom.xml):

      xml 复制代码
      <build>
          <plugins>
              <plugin>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-maven-plugin</artifactId>
                  <!-- 自动寻找 main 方法作为入口 -->
              </plugin>
          </plugins>
      </build>
    2. 打包mvn clean package

    3. 运行java -jar target/springboot_helloworld.jar

2. WAR 方式 (传统部署)
  • 场景:需部署到外部独立的 Tomcat/Jetty 服务器。
  • 步骤详解
    1. 修改打包方式

      xml 复制代码
      <packaging>war</packaging>
    2. 排除内嵌 Tomcat (防止冲突):

      xml 复制代码
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-tomcat</artifactId>
          <scope>provided</scope> <!-- 打包时不包含,运行时由外部 Tomcat 提供 -->
      </dependency>
    3. 修改启动类 (继承初始化器):

      java 复制代码
      import org.springframework.boot.builder.SpringApplicationBuilder;
      import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
      
      // 必须继承 SpringBootServletInitializer
      public class SpringBootHelloworldApp extends SpringBootServletInitializer {
          
          @Override
          protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
              // 指向当前的启动类
              return builder.sources(SpringBootHelloworldApp.class);
          }
      
          // 保留 main 方法,方便本地调试
          public static void main(String[] args) {
              SpringApplication.run(SpringBootHelloworldApp.class, args);
          }
      }
    4. 部署 :将生成的 .war 包复制到外部 Tomcat 的 webapps/ 目录下,启动 Tomcat 即可。


🛠️ 模块三:进阶整合 (异常、测试、多环境、日志)

一、全局异常处理器

1. 前后端分离架构 (重点 🔥)

返回 JSON 数据给前端,而不是跳转错误页面。

  • 核心注解
    • @ControllerAdvice:全局增强,拦截所有 Controller 的异常。
    • @ExceptionHandler:指定捕获的异常类型。
    • @ResponseBody:返回数据而非视图。
java 复制代码
package com.hg.exception;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
public class GlobalExceptionResolver {

    // 捕获所有 Exception 类型的异常
    @ExceptionHandler({Exception.class})
    @ResponseBody
    public Map<String, Object> handleException(Exception e) {
        e.printStackTrace(); // 控制台打印堆栈
        
        Map<String, Object> result = new HashMap<>();
        result.put("code", 500);
        result.put("msg", "服务器内部错误:" + e.getMessage());
        result.put("data", null);
        
        return result;
    }
    
    // 也可以针对特定异常做处理
    @ExceptionHandler(ArithmeticException.class)
    @ResponseBody
    public Map<String, Object> handleArithmeticException(ArithmeticException e) {
        Map<String, Object> result = new HashMap<>();
        result.put("code", 400);
        result.put("msg", "数学计算错误:" + e.getMessage());
        return result;
    }
}
2. 非前后端分离 (了解)

实现 HandlerExceptionResolver 接口,返回 ModelAndView 跳转到错误页。
(注:现代开发极少使用此方式,通常直接用上面的注解方式)

二、整合 JUnit 单元测试

1. 依赖引入
xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
2. 三种启动方式的对比与代码

方式 A:Main 方法手动启动 (原始)

java 复制代码
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = ctx.getBean(UserService.class);

方式 B:Spring 整合 JUnit (老式)

java 复制代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class OldSpringTest { ... }

方式 C:Spring Boot 整合 JUnit (推荐 ✅)

  • 特点@SpringBootTest 自动加载配置,无需 XML,无需 Runner。
java 复制代码
package com.hg.test;

import com.hg.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

// 加载完整的 Spring 上下文,默认查找启动类
@SpringBootTest(classes = SpringbootHelloworldApp.class) 
public class SpringbootJunitTest {

    @Autowired
    private UserService userService;

    @Test
    public void testFindUser() {
        // 直接调用,如果配置正确,userService 不为 null
        assert userService != null;
        System.out.println("测试通过!用户服务已注入。");
        // 执行具体业务逻辑测试
        // User user = userService.findById(1L);
    }
}

三、多环境配置 (Profiles)

解决开发、测试、生产环境配置不同的问题。

1. 文件命名规则

主文件:application.yml

子文件:application-环境名.yml

  • application-dev.yml (开发环境)
  • application-test.yml (测试环境)
  • application-prod.yml (生产环境)
2. 配置文件内容示例

application-dev.yml:

yaml 复制代码
server:
  port: 8081
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/dev_db
    username: dev_user
    password: dev_pass

application-test.yml:

yaml 复制代码
server:
  port: 8082
spring:
  datasource:
    url: jdbc:mysql://test-server:3306/test_db
    username: test_user
    password: test_pass

application-prod.yml:

yaml 复制代码
server:
  port: 8083
spring:
  datasource:
    url: jdbc:mysql://prod-cluster:3306/prod_db
    username: prod_user
    password: prod_strong_pass
3. 激活环境

在主文件 application.yml 中指定默认激活的环境:

yaml 复制代码
spring:
  profiles:
    active: dev  # 默认激活 dev 环境,修改此处可切换

💡 命令行动态切换

打包后运行:java -jar app.jar --spring.profiles.active=prod

这样无需修改配置文件即可切换环境。

四、整合 Logback 日志

Spring Boot 默认使用 Logback 作为日志框架,无需额外引入依赖。

1. 配置文件 src/main/resources/logback-spring.xml

使用 -spring 后缀可以让 Logback 读取 Spring Boot 的配置(如 ${APP_NAME})。

xml 复制代码
<configuration scan="true" scanPeriod="30 seconds">
    
    <!-- 定义变量 -->
    <property name="LOG_HOME" value="./logs"/>
    <property name="APP_NAME" value="springboot_helloworld"/>

    <!-- 控制台输出格式 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 文件输出:按天滚动 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_HOME}/${APP_NAME}.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每天生成一个文件,保留30天 -->
            <fileNamePattern>${LOG_HOME}/${APP_NAME}.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 根节点配置 -->
    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="FILE"/>
    </root>

    <!-- 单独配置某个包的日志级别 -->
    <logger name="com.hg.service" level="DEBUG"/>
    <logger name="org.springframework.web" level="INFO"/>
    
</configuration>
2. 代码中使用日志

推荐使用 Lombok 的 @Slf4j 简化代码。

java 复制代码
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j // 自动生成 private static final Logger log = ...
@RestController
public class LogDemoController {

    @GetMapping("/log-test")
    public String logTest() {
        log.trace("这是 TRACE 级别日志 (最详细)");
        log.debug("这是 DEBUG 级别日志 (调试用)");
        log.info("这是 INFO 级别日志 (一般信息)");
        log.warn("这是 WARN 级别日志 (警告)");
        log.error("这是 ERROR 级别日志 (错误)");
        
        try {
            int i = 1 / 0;
        } catch (Exception e) {
            log.error("发生算术异常", e); // 自动打印堆栈
        }
        
        return "日志已记录,请查看 logs 目录或控制台";
    }
}

🎁 额外补充知识点 (加分项)

1. @ConfigurationProperties vs @Value

  • @Value:逐个注入,适合少量配置。
  • @ConfigurationProperties:批量注入,支持松散绑定(my-prop 对应 myProp),支持 JSR303 校验,推荐用于复杂配置
java 复制代码
@Component
@ConfigurationProperties(prefix = "myapp")
@Data // Lombok
public class MyAppProperties {
    private String name;
    private int version;
    private List<String> features;
}
// yml: myapp.name=xxx, myapp.features[0]=a

2. Spring Boot 自动配置原理简述

  • 启动类上的 @EnableAutoConfiguration 是关键。
  • 它通过 SPI 机制加载 META-INF/spring.factories (Spring Boot 2.7+ 改为 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports) 中的所有配置类。
  • 这些配置类上使用 @ConditionalOnClass, @ConditionalOnMissingBean 等注解,按需加载 。例如:只有当类路径下有 JdbcTemplate 类时,才自动配置数据源相关 Bean。

3. 热部署 (DevTools)

开发效率神器,修改代码后自动重启应用。

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>
  • IDEA 设置:File -> Settings -> Build, Execution, Deployment -> Compiler -> 勾选 "Build project automatically"。
  • Registry:Ctrl+Shift+Alt+/ -> Registry -> 勾选 "compiler.automake.allow.when.app.running"。

相关推荐
小江的记录本4 小时前
【Logback】Logback 日志框架 与 SLF4J绑定、三层模块、MDC链路追踪、异步日志、滚动策略
java·spring boot·后端·spring·log4j·maven·logback
studyForMokey4 小时前
【Android面试】Handler专题
android·java·面试
难忘经典4 小时前
springboot中配置logback-spring.xml
spring boot·spring·logback
huabiangaozhi4 小时前
SpringBoot + vue 管理系统
vue.js·spring boot·后端
ruiang4 小时前
Spring Boot 3.3.4 升级导致 Logback 之前回滚策略配置不兼容问题解决
java·spring boot·logback
yoothey4 小时前
我对Java Web开发中多线程的困惑
java·开发语言·前端
xiufeia4 小时前
JMeter
java·jmeter·tomcat·高并发
楼田莉子4 小时前
CMake学习:CMake在静态库工程场景上应用
开发语言·c++·后端·学习·软件构建
断春风4 小时前
深入了解 Java 日志框架:SLF4J 和 Logback
java·架构·logback