Spring Boot 深入解析:核心原理与实践应用
一、Spring Boot 基础原理
1.1 自动配置机制
1.1.1 依赖管理
Spring Boot 通过父工程 spring-boot-dependencies 统一管理所有核心依赖的版本。当我们引入 Spring Boot 依赖时,无需手动指定版本号,这是因为这些版本信息已经在仓库中预先配置好了。
1.1.2 启动器(Starter)
启动器本质上是 Spring Boot 的功能场景集合。例如,spring-boot-starter-web 会自动导入 Web 开发所需的所有依赖。Spring Boot 将各种功能场景封装成一个个启动器,开发者只需根据需求选择相应的启动器即可。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
1.1.3 主程序类
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
核心注解解析:
@SpringBootConfiguration:Spring Boot 配置类,相当于@Configuration,而@Configuration本质是@Component的特化@EnableAutoConfiguration:启用自动配置,包含:@AutoConfigurationPackage:自动配置包,通过@Import(Registrar.class)导入注册类@Import(AutoConfigurationImportSelector.class):自动配置导入选择器
1.1.4 配置文件
Spring Boot 使用全局配置文件,文件名固定为 application.properties 或 application.yaml。
application.properties:语法结构为key=valueapplication.yaml:语法结构为key: 空格 value
配置文件作用:修改 Spring Boot 自动配置的默认值,因为 Spring Boot 在底层已经为我们自动配置好了大部分常用功能。
二、YAML 配置详解
2.1 语法基础
# YAML 对空格要求严格,冒号后需加空格
# 基本键值对
name: 李四
# 对象格式
user:
name: 李四
age: 20
# 行内对象写法
user: {name: 李四, age: 20}
# 数组格式
hobbies:
- 阅读
- 游泳
- 编程
# 行内数组写法
hobbies: [阅读,游泳,编程]
2.2 属性注入方式
2.2.1 传统注解方式
@Component
public class UserInfo {
@Value("李四")
private String name;
// 其他属性省略...
}
2.2.2 YAML 绑定方式(推荐)
@Component
@ConfigurationProperties(prefix = "user")
public class UserInfo {
private String name;
private Integer age;
private Boolean active;
private LocalDate birthday;
private Map<String, Object> attributes;
private List<String> hobbies;
private Pet pet;
// Getter 和 Setter 方法
}
# YAML 配置
user:
name: 李四
age: 20
active: true
birthday: 2000-01-01
attributes: {key1: value1, key2: value2}
hobbies: [阅读,游泳,编程]
pet:
name: 小白
age: 2
2.2.3 自定义属性文件
@Component
@PropertySource(value = "classpath:custom.properties")
public class UserInfo {
@Value("${username}")
private String name;
// 其他属性省略...
}
2.2.4 辅助功能
- 消除 IDEA 提示:添加依赖消除
@ConfigurationProperties的警告<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> - 日期解析:处理
LocalDate类型@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) private LocalDate birthday; - 数据校验:JSR303 校验
@Component @ConfigurationProperties(prefix = "user") @Validated public class UserInfo { @Email(message = "邮箱格式不正确") private String email; // 其他属性省略... } - 热加载:开发时自动重启应用
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency>
2.2.5 最佳实践
- 优先使用 YAML 格式配置文件
- 仅需获取单个值时使用
@Value - 需要批量映射配置到 JavaBean 时使用
@ConfigurationProperties
三、配置文件优先级与多环境
3.1 配置文件加载优先级
file:./config/(项目目录下的 config 文件夹)file:./(项目根目录)classpath:/config(resources 目录下的 config 文件夹)classpath:/(resources 目录)
Spring Boot 默认使用最低优先级,即 resources 目录下的配置文件。
3.2 多环境配置
server:
port: 8080
spring:
profiles:
active: dev
---
server:
port: 8081
spring:
profiles: test
---
server:
port: 8082
spring:
profiles: prod
3.3 自动配置原理
- Spring Boot 启动时加载大量自动配置类
- 检查所需功能是否在默认自动配置类中 3. 查看自动配置类中配置的组件,若所需组件已存在,则无需手动配置 4. 容器添加组件时从属性类中获取配置值,只需在配置文件中指定这些值
xxxAutoConfiguration:自动配置类,向容器添加组件
xxxProperties:封装配置文件相关属性
通过设置 debug=true 可查看自动配置报告,了解哪些配置类生效(正匹配)或未生效(负匹配)。
四、Spring Boot Web 开发
4.1 静态资源处理
Spring Boot 支持多种静态资源访问方式:
webjars:http://localhost:8080/webjars/jquery/3.6.0/jquery.jspublic、static、**、resources:http://localhost:8080/
优先级:resources > static(默认) > public
4.2 首页与模板
templates 目录下的页面需通过 Controller 访问,需引入模板引擎(如 Thymeleaf):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
4.3 SpringMVC 扩展
4.3.1 方式一:自定义组件
@Configuration
public class WebMvcConfig {
@Bean
public ViewResolver customViewResolver() {
return new CustomViewResolver();
}
public static class CustomViewResolver implements ViewResolver {
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
// 自定义视图解析逻辑
return null;
}
}
}
4.3.2 方式二:实现 WebMvcConfigurer(推荐)
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/home").setViewName("index");
registry.addViewController("/login").setViewName("login");
}
}
五、数据持久化集成
5.1 Druid 数据源配置
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
5.2 MyBatis 集成
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
5.3 实体类与映射
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee {
private Integer id;
private String name;
private String position;
private LocalDate hireDate;
}
5.4 Mapper 接口与 XML
@Mapper
@Repository
public interface EmployeeMapper {
List<Employee> findAll();
}
<?xml version="1.0" encoding="UTF-8"?>
<mapper namespace="com.example.mapper.EmployeeMapper">
<resultMap id="employeeMap" type="Employee">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="position" property="position"/>
<result column="hire_date" property="hireDate"/>
</resultMap>
<select id="findAll" resultMap="employeeMap">
SELECT id, name, position, hire_date
FROM employees
</select>
</mapper>
5.5 配置文件
# MyBatis 配置
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.example.entity
configuration:
map-underscore-to-camel-case: true
# 数据源配置
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql:///company_db?useUnicode=true&characterEncoding=utf8
username: root
password: password
type: com.alibaba.druid.pool.DruidDataSource
# Druid 配置
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
六、安全框架集成
6.1 Spring Security 配置
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasRole("USER")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/dashboard")
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/")
.permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin").password(passwordEncoder().encode("admin123")).roles("ADMIN")
.and()
.withUser("user").password(passwordEncoder().encode("user123")).roles("USER");
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
6.2 Shiro 安全框架
6.2.1 依赖引入
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.7.1</version>
</dependency>
6.2.2 自定义 Realm
public class CustomRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// 授权逻辑
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 认证逻辑
UsernamePasswordToken userToken = (UsernamePasswordToken) token;
User user = userService.findByUsername(userToken.getUsername());
if (user == null) {
return null; // 用户不存在
}
return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
}
}
6.2.3 Shiro 配置
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(securityManager);
Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/login", "anon");
filterMap.put("/doLogin", "anon");
filterMap.put("/**", "authc");
bean.setFilterChainDefinitionMap(filterMap);
bean.setLoginUrl("/login");
bean.setUnauthorizedUrl("/unauthorized");
return bean;
}
@Bean
public DefaultWebSecurityManager securityManager(CustomRealm customRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(customRealm);
return securityManager;
}
@Bean
public CustomRealm customRealm() {
return new CustomRealm();
}
}
七、日志配置
7.1 Log4j2 配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
7.2 log4j2.xml 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Properties>
<Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Property>
</Properties>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="${LOG_PATTERN}"/>
</Console>
<RollingFile name="RollingFile" fileName="logs/app.log"
filePattern="logs/app-%d{yyyy-MM-dd}-%i.log">
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="10 MB"/>
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Console"/>
<AppenderRef ref="RollingFile"/>
</Root>
<Logger name="com.example" level="debug" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="RollingFile"/>
</Logger>
</Loggers>
</Configuration>