Spring Boot 之所以能成为 Java 开发者的 “心头好”,很大程度上归功于它化繁为简的注解体系—— 原本需要大量 XML 配置的工作,如今只需几个注解就能轻松搞定。
一、启动类与核心配置:项目的 “启动引擎”
Spring Boot 项目的入口是启动类,而核心注解定义了项目的整体配置规则。
1. @SpringBootApplication:最核心的启动注解
这是 Spring Boot 项目的 “标志性注解”,它是 @SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan 三个注解的组合,作用是:
- 标记当前类为配置类(等价于@Configuration);
- 开启自动配置(Spring Boot 根据依赖自动配置 Bean);
- 扫描当前包及子包下的组件(如 @Component、@Service 等标注的类)。
示例:最简启动类
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
一行注解,就完成了 “配置 + 自动配置 + 组件扫描” 三大核心工作~
2. @EnableAutoConfiguration:自动配置的 “开关”
单独使用时,它会根据项目依赖自动配置对应的 Bean(比如引入 spring-boot-starter-web
,就会自动配置 Web 相关的 Tomcat、Spring MVC 等 Bean)。通常无需单独写,因为 @SpringBootApplication 已经包含了它。
3. @ComponentScan:组件扫描的 “范围定义”
指定 Spring 扫描组件(@Component、@Service、@Controller 等)的包路径。若不指定,默认扫描当前类所在包及子包。
示例(指定扫描多个包):
@ComponentScan(basePackages = {"com.example.service", "com.example.controller"})
@SpringBootApplication
public class MyApplication {
// ...
}
4. @Configuration:自定义配置类的 “标识”
标记一个类为配置类,作用类似于传统 Spring 中的 XML 配置文件。在配置类中,可通过@Bean 注解定义 Bean。
示例:自定义 RedisTemplate Bean
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 配置序列化规则...
return template;
}
}
二、Web 开发:前后端交互的 “桥梁”
Spring Boot 对 Web 开发的支持非常友好,注解让接口开发变得极其简洁。
1.@RestController: 接口开发的 “万能注解”
它是 @Controller + @ResponseBody 的组合,作用是:
- 标记类为控制器(处理 HTTP 请求);
- 让所有方法的返回值直接作为 HTTP 响应体(如 JSON、字符串),无需再单独加 @ResponseBody。
示例:返回 JSON 数据的接口
@RestController
@RequestMapping("/api/user")
public class UserController {
@GetMapping("/list")
public List<User> listUsers() {
return userService.findAll(); // 自动转 JSON 返回
}
}
2. @RequestMapping:请求映射
- @RequestMapping:标注请求的URL 路径、请求方法(GET/POST 等);
- @GetMapping / @PostMapping:是 @RequestMapping 的快捷方式(分别对应 GET、POST 请求)。
示例:处理 POST 请求的接口
@PostMapping("/save")
public Result saveUser(@RequestBody User user) {
userService.save(user);
return Result.success("保存成功");
}
3. @RequestParam / @PathVariable / @RequestBody:参数绑定
这三个注解用于接收前端传递的参数,对应 “URL 参数”“路径参数”“请求体(JSON/XML)” 三种场景,在 Spring Boot 中用法与 Spring MVC 完全一致。
三、依赖注入与组件管理:项目的 “零件组装”
Spring 的核心思想是 “依赖注入(DI)”,这些注解让 “零件(Bean)” 的组装变得灵活。
1. @Autowired / @Resource:依赖注入
两者都用于从 Spring 容器中获取 Bean 并注入到字段 / 方法中,简化对象创建与依赖管理。
- @Autowired:Spring 提供的注解,默认按类型注入;
- @Resource:JDK 提供的注解,默认按名称注入(可通过 name 属性指定 Bean 名称)。
示例:注入 UserService
@Service
public class UserServiceImpl implements UserService {
// 业务逻辑...
}
@RestController
public class UserController {
@Autowired
private UserService userService; // 自动注入 UserService Bean
}
2. @Component / @Service / @Repository / @Controller:组件标识
这些注解用于标记类为 Spring 管理的 “组件(Bean)”,让 Spring 自动扫描并纳入容器管理:
- @Component:通用组件标识;
- @Service:标记业务层组件;
- @Repository:标记 ** 数据访问层(DAO)** 组件,还能触发持久层异常转换;
- @Controller:标记控制层组件(处理 HTTP 请求)。
示例:各层组件标记
@Repository
public class UserDaoImpl implements UserDao { /* DAO 逻辑 */ }
@Service
public class UserServiceImpl implements UserService { /* 业务逻辑 */ }
@Controller
public class UserController { /* 控制层逻辑 */ }
四、配置加载与属性绑定:灵活的 “配置中心”
Spring Boot 支持从 application.yml/application.properties 等文件加载配置,这些注解让 “配置到Java 对象” 的绑定更便捷。
1. @ConfigurationProperties:批量绑定配置属性
将配置文件中的一组属性批量绑定到 Java 类的字段上,适合需要绑定多个配置的场景(如数据库连接、第三方服务配置)。
示例:绑定数据库配置
配置文件(application.yml):
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: root
password: 123456
Java 类:
@ConfigurationProperties(prefix = "spring.datasource")
@Component
@Data // Lombok 注解,生成 getter/setter
public class DataSourceProps {
private String url;
private String username;
private String password;
}
这样,url、username、password就会自动从配置文件中读取。
2. @Value:单个属性的 “精准绑定”
用于绑定单个配置属性,支持 “SpEL 表达式” 和 “默认值”。
示例:绑定服务器端口
@Component
public class ServerInfo {
@Value("${server.port:8080}") // 从配置取 server.port,默认 8080
private Integer port;
}
3. @PropertySource:加载自定义配置文件
指定要加载的自定义配置文件(如 config/user.properties),配合@Value 或 @ConfigurationProperties 使用。
@PropertySource("classpath:config/user.properties")
@Configuration
public class UserConfig {
@Value("${user.max-count}")
private Integer maxCount;
}
五、数据访问与持久化:和数据库 “打交道”
Spring Boot 整合 JPA、MyBatis 等框架时,这些注解让数据库操作更简洁。
1. JPA 相关注解(以 Hibernate 为例)
- @Entity:标记类为数据库实体类(对应一张表);
- @Table(name = "xxx"):指定实体类对应的数据表名;
- @Id:标记主键字段;
- @GeneratedValue:指定主键生成策略(如自增);
- @Column(name = "xxx"):指定字段对应的数据表列名。
示例:用户实体类
@Entity
@Table(name = "t_user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // 自增主键
private Long id;
@Column(name = "user_name")
private String username;
private Integer age;
// getter/setter...
}
2. @Transactional:声明式事务
标记方法或类,让方法执行时自动纳入事务管理(异常时回滚,正常时提交)。
示例:添加事务的业务方法
@Service
public class UserService {
@Autowired
private UserDao userDao;
@Transactional
public void saveUserWithTx(User user) {
userDao.save(user);
// 若后续逻辑抛异常,save 操作会回滚
}
}
六、AOP 与切面编程:无侵入式 “增强”
AOP(面向切面编程)能在不修改原有代码的情况下,对方法进行 “增强”(如日志、权限校验、事务)。
1. @Aspect:标记切面类
标记一个类为切面类,在其中定义 “切点” 和 “通知”。
2. @Pointcut:定义切点
指定哪些方法需要被 “切面” 增强(通过表达式匹配方法)。
3. @Before / @After / @Around:通知类型
- @Before:目标方法执行前执行增强逻辑;
- @After:目标方法执行后(无论是否异常)执行增强逻辑;
- @Around:目标方法执行前后都能执行增强逻辑(最灵活)。
示例:记录方法执行时间的切面
@Aspect
@Component
public class TimeLogAspect {
@Pointcut("execution(* com.example.service.*.*(..))") // 匹配 service 包下所有方法
public void serviceMethods() {}
@Around("serviceMethods()")
public Object logTime(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
try {
return joinPoint.proceed(); // 执行目标方法
} finally {
long cost = System.currentTimeMillis() - start;
System.out.println(joinPoint.getSignature() + " 执行耗时:" + cost + "ms");
}
}
}
七、异步与定时任务:非阻塞与自动化
1. @Async:异步执行方法
让方法异步执行(放入线程池,不阻塞主线程),需配合 @EnableAsync(在启动类上标注)使用。
示例:异步发送邮件
@Service
public class MailService {
@Async
public void sendMail(String to, String content) {
// 发送邮件逻辑(异步执行,主线程不等待)
}
}
2. @Scheduled:定时任务
让方法按指定规则定时执行,需配合 @EnableScheduling(在启动类上标注)使用。
示例:每天凌晨 1 点清理缓存
@Component
public class CacheCleaner {
@Scheduled(cron = "0 0 1 * * ?") // cron 表达式:每天 1 点执行
public void cleanCache() {
// 清理缓存逻辑
}
}