Spring框架注解及使用

Bean声明与装配注解

@Component - 通用组件注解

这个注解是Spring通用的组件注解,它是(@Service,@Repository,@Controller)的父注解,用于标识组件并交给Spring管理。

使用场景:当你的类不属于任何特定分层(如工具类、通用组件)时使用。

举例:

1
2
3
4
5
6
7
8
9
import org.springframework.stereotype.Component;

// 标记该类为 Spring 组件,IoC 容器会创建其实例
@Component
public class CommonUtils {
public String formatDate() {
return "2026-01-11";
}
}

@Service - 服务层组件
专门用于逻辑业务层(Service层)的注解,本质是@Component的别名,但是更加具有语义化(标识用于Service层)

使用场景:所有处理业务逻辑的类。

附加价值:Spring 对 @Service 有特殊的异常转换支持(如将数据层异常转为 Spring 统一的 DataAccessException)。

举例:

1
2
3
4
5
6
7
8
9
import org.springframework.stereotype.Service;

@Service
public class UserService {
// 业务逻辑:用户注册、登录等
public boolean login(String username, String password) {
return "admin".equals(username) && "123456".equals(password);
}
}

@Repository - 数据访问层组件
专门用于标识数据访问层(DAO层或者Repository层)的标识注解,本质上还是@Component注解,具有特定的语义(专门用于标识数据访问层)

使用场景:操作数据库的类(UserDao、OrderRepository等)

附加价值:Spring 会自动将 @Repository 标注的类中抛出的原生持久化异常(如 JDBC、MyBatis 异常)转换为 Spring 统一的 DataAccessException 异常体系。

举例:

1
2
3
4
5
6
7
8
9
import org.springframework.stereotype.Repository;

@Repository
public class UserRepository {
// 数据访问逻辑:查询、插入、更新用户数据
public String getUserById(Long id) {
return "用户" + id;
}
}

@Controller - Web 控制器组件
专门用于Web层(控制层)的注解,标识一个类是Spring MVC的控制器,用于处理Http请求。

核心能力:配合 @RequestMapping 等注解映射请求路径,默认返回视图(如 JSP/HTML)

使用场景:传统 MVC 开发中,需要返回页面的控制器。

举例:

1
2
3
4
5
6
7
8
9
10
11
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class PageController {
// 处理 /index 请求,返回名为 "index" 的视图(如 index.jsp)
@GetMapping("/index")
public String index() {
return "index";
}
}

@RestController - REST 控制器(包含 @Controller 和 @ResponseBody)
作用:专门用于开发 RESTful API 的控制器注解,是 @Controller + @ResponseBody 的组合注解。

核心能力:所有方法的返回值都会被自动序列化为 JSON/XML 格式,直接写入 HTTP 响应体,而非返回视图。

使用场景:前后端分离项目中,提供接口(返回 JSON 数据)的控制器。

举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ApiController {
// 处理 /api/user 请求,返回 JSON 格式的用户数据
@GetMapping("/api/user")
public User getUser() {
return new User("admin", 20); // 自动转为 {"username":"admin","age":20}
}

// 内部静态类,模拟用户实体
static class User {
private String username;
private int age;
// 构造器、getter/setter 省略
public User(String username, int age) {
this.username = username;
this.age = age;
}
}
}

@Configuration - 配置类
作用:标识一个类是 Spring 的配置类,替代传统的 XML 配置文件(如 applicationContext.xml)。

核心能力:配置类中可以通过 @Bean 注解声明自定义的 Bean,也可以导入其他配置类、扫描组件等。

使用场景:需要手动配置 Bean(如第三方组件、自定义对象)时使用。

举例:

1
2
3
4
5
6
7
8
9
import org.springframework.context.annotation.Configuration;

// 标识这是一个 Spring 配置类
@Configuration
// 可选:指定组件扫描路径,替代 XML 中的 <context:component-scan>
// @ComponentScan("com.example.demo")
public class AppConfig {
// 这里可以用 @Bean 声明自定义 Bean
}

@Bean - 声明 Bean
作用:用于 @Configuration 类的方法上,手动声明一个 Bean,Spring 会将该方法的返回值纳入 IoC 容器管理。

核心能力:可以自定义 Bean 的创建逻辑(如初始化参数、依赖注入),Bean 的默认名称是方法名,也可通过 name/value 属性指定。

使用场景:创建第三方类的实例(如 RedisTemplate、DataSource)、自定义复杂对象的实例时。

举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {
// 声明一个名为 "myDataSource" 的 Bean,Spring 会管理其生命周期
@Bean(name = "myDataSource")
public DataSource dataSource() {
DruidDataSource ds = new DruidDataSource();
ds.setUrl("jdbc:mysql://localhost:3306/test");
ds.setUsername("root");
ds.setPassword("123456");
return ds;
}
}

@Scope - 指定 Bean 作用域
作用:指定 Bean 的作用域(生命周期范围),控制 Spring 创建 Bean 实例的数量和时机。
常用取值:

取值 含义
singleton 单例(默认):IoC 容器中只有一个 Bean 实例,全局共享
prototype 原型:每次获取 Bean 时都创建新实例
request Web 环境:每个 HTTP 请求创建一个新实例
session Web 环境:每个 HTTP Session 创建一个新实例
application Web 环境:整个 Web 应用(ServletContext)共享一个实例
  1. singleton (单例) —— 默认规则
  • 含义: 在整个 Spring 容器中,这个 Bean 只有一个。
  • 通俗理解: 就像共享单车。全城(容器)只有这一辆编号为 001 的车,谁扫码(请求 Bean)骑的都是这一辆。你改了车铃,下一个人骑的时候铃也是改过的。
  • 使用场景: 绝大多数无状态的类(如 @Service、@Controller、@Repository)。
  1. prototype (原型) —— 每次都新做
  • 含义: 每次获取(通过 getBean() 或注入)时,Spring 都会重新创建一个全新的实例。
  • 通俗理解: 就像外卖奶茶店。每个人下单(请求 Bean),店里都会现场现做一杯全新的给你,你喝你的,他喝他的,互不影响。
  • 使用场景: 含有多线程操作或带有状态(成员变量会变)的类。
  1. Web 环境专属作用域
    注意: 下面这三个必须在 Web 项目(Spring MVC/WebFlux)中才有效。
  • request (请求)
    • 含义: 每个 HTTP 请求都会创建一个新的 Bean,请求结束,Bean 销毁。
    • 通俗理解: 就像餐厅的桌布。客人 A 进店吃饭(发起请求),铺一块新桌布;客人 A 吃完走了,桌布撤掉。客人 B 来了,再铺一块新的。
  • session (会话)
    • 含义: 在同一个 HTTP Session 中,Bean 是共享的。
    • 通俗理解: 就像酒店的房卡。你在酒店住的这几天(同一个 Session),无论你进出房间多少次,用的都是同一张卡。直到你退房,这张卡才失效。
  • application (应用)
    • 含义: 整个 Web 应用(ServletContext)生命周期内只有一个。
    • 通俗理解: 就像酒店的大堂经理。只要酒店开门营业,大堂经理就在那里,所有住客面对的都是同一个大堂经理。

举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

@Configuration
public class ScopeConfig {
// 原型 Bean:每次 getBean() 都返回新实例
@Bean
@Scope("prototype")
public User user() {
return new User();
}
}

@Lazy - 延迟初始化
作用:指定 Bean 为延迟初始化,即 Bean 不会在 Spring 容器启动时创建,而是在第一次被使用时(如 getBean()、依赖注入)才创建。

适用场景:

  • 单例 Bean(默认立即初始化)想延迟创建,减少容器启动时间;
  • 解决循环依赖的部分场景;
  • 资源密集型 Bean(如大对象),避免启动时占用资源。

举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

@Configuration
public class LazyConfig {
// 延迟初始化:容器启动时不创建,第一次使用时才创建
@Bean
@Lazy
public HeavyService heavyService() {
return new HeavyService(); // 假设这是一个初始化耗时的类
}
}

@Primary - 首选 Bean
作用:当存在多个同类型的 Bean 时,指定 “首选 Bean”,Spring 自动注入时会优先选择标注了 @Primary 的 Bean。

使用场景:解决 “同类型多个 Bean 注入时的歧义问题”。

举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

@Configuration
public class PrimaryConfig {
// 首选 Bean:注入 DataSource 时优先选择这个
@Bean
@Primary
public DataSource primaryDataSource() {
return new DruidDataSource();
}

// 非首选 Bean
@Bean
public DataSource secondaryDataSource() {
return new HikariDataSource();
}
}

// 注入时,会自动选择 primaryDataSource
@Service
public class OrderService {
@Autowired
private DataSource dataSource; // 注入的是 primaryDataSource
}

@DependsOn - 依赖关系
作用:强制指定 Bean 的初始化顺序,确保标注 @DependsOn 的 Bean 被初始化前,其依赖的 Bean 已经先初始化完成。

适用场景:某些 Bean 的初始化依赖其他 Bean 先完成(如 A Bean 需要读取 B Bean 初始化的配置)。

举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

@Configuration
public class DependsOnConfig {
// 先初始化 configBean
@Bean
public ConfigBean configBean() {
return new ConfigBean();
}

// 依赖 configBean,确保 configBean 先初始化
@Bean
@DependsOn("configBean")
public BusinessBean businessBean() {
return new BusinessBean();
}
}

依赖注入

@Autowired - 自动装配
Spring 框架原生注解,用于自动注入依赖的 Bean,默认按照 类型(Type) 匹配 IoC 容器中的 Bean,完成依赖注入。

注入位置:可标注在构造器、字段、setter 方法、普通方法上;

默认规则:默认要求注入的 Bean 必须存在(否则抛 NoSuchBeanDefinitionException),可通过 required = false 关闭强制检查;

优先级:

  • 先按类型匹配(如注入 UserService 类型,找容器中所有 UserService 类型的 Bean);
  • 若找到多个同类型 Bean,会尝试按字段名 / 方法参数名匹配 Bean 名称;
  • 若仍匹配失败,需配合 @Qualifier 指定 Bean 名称。

举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class OrderService {
// 1. 字段注入(最简洁,推荐度中等,缺点:无法实现不可变字段)
@Autowired(required = false) // required=false:没有该Bean也不报错
private UserService userService;

// 2. 构造器注入(推荐!支持不可变字段,Spring 4.3+ 单构造器可省略 @Autowired)
private final OrderRepository orderRepository;

@Autowired // 单构造器时可省略
public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}

// 3. Setter 方法注入
private LogService logService;

@Autowired
public void setLogService(LogService logService) {
this.logService = logService;
}
}

@Qualifier - 指定 Bean 名称
配合 @Autowired 使用,解决同类型多个 Bean 注入的歧义问题,明确指定要注入的 Bean 名称(而非按类型 / 字段名匹配)。

使用场景:当 IoC 容器中有多个同类型的 Bean 时(比如有两个 DataSource 类型的 Bean:primaryDataSource 和 secondaryDataSource),仅用 @Autowired 会报错,需用 @Qualifier 指定名称。

举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class DataService {
// 注入名称为 "secondaryDataSource" 的 DataSource Bean
@Autowired
@Qualifier("secondaryDataSource")
private DataSource dataSource;
}

// 配置类中声明多个同类型 Bean
@Configuration
public class DataSourceConfig {
@Bean("primaryDataSource")
public DataSource primaryDataSource() {
return new DruidDataSource();
}

@Bean("secondaryDataSource")
public DataSource secondaryDataSource() {
return new HikariDataSource();
}
}

@Value - 注入属性值
核心作用:用于注入外部配置的属性值(如 application.properties/application.yml 中的配置、系统环境变量、字面量等),支持 SpEL(Spring 表达式语言)。

常用注入场景

注入类型 示例写法 说明
字面量 @Value(“hello”) 直接注入字符串 “hello”
配置文件属性 @Value(“${server.port}”) 注入配置文件中 server.port 的值
系统环境变量 @Value(“${JAVA_HOME}”) 注入系统环境变量 JAVA_HOME
SpEL 表达式 @Value(“#{100 + 20}”) 执行表达式,注入 120
默认值 @Value(“${app.name:默认名称}”) 配置不存在时用默认值

举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class AppConfigProperties {
// 注入配置文件中的 app.name,不存在则用 "demo-app"
@Value("${app.name:demo-app}")
private String appName;

// 注入服务器端口(来自 application.properties)
@Value("${server.port:8080}")
private int port;

// 注入 SpEL 表达式结果:计算 10*20
@Value("#{10 * 20}")
private int calcResult;

// 注入系统环境变量
@Value("${USERNAME}")
private String osUsername;
}

@Resource - JSR-250 注解
核心作用:JSR-250 规范定义的依赖注入注解(非 Spring 原生),用于注入 Bean,默认按 名称(Name) 匹配,名称匹配失败时按 类型(Type) 匹配。

与 @Autowired 的核心区别

特性 @Autowired @Resource
所属规范 Spring 原生 JSR-250(Java 标准)
默认匹配规则 按类型 → 按名称 按名称 → 按类型
支持指定名称 需配合 @Qualifier 直接用 name 属性(@Resource(name=”xxx”))
支持required=false 支持(@Autowired(required=false)) 不支持(找不到 Bean 直接报错)
注入位置 构造器、字段、方法 字段、setter 方法(不支持构造器)

举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
import javax.annotation.Resource;
import org.springframework.stereotype.Service;

@Service
public class UserService {
// 1. 按名称注入:找名称为 "userRepository" 的 Bean
@Resource(name = "userRepository")
private UserRepository userRepo;

// 2. 不指定 name:按字段名 "logService" 匹配 Bean 名称
@Resource
private LogService logService;
}

@Inject - JSR-330 注解
核心作用:JSR-330 规范定义的依赖注入注解(Java EE 标准),功能与 @Autowired 类似,默认按 类型 匹配,需配合 @Named 指定 Bean 名称(替代 @Qualifier)。

核心特点

  • 无 required 属性,若找不到 Bean 直接抛异常;
  • 需导入额外依赖(Spring 已内置,无需手动加);
  • 更符合 Java 标准,可跨框架使用(如 Guice 也支持)。

与 @Autowired 的对比

特性 @Autowired @Inject
所属规范 Spring 原生 JSR-330(Java 标准)
默认匹配规则 按类型 按类型
指定 Bean 名称 配合 @Qualifier 配合 @Named
required 特性 支持 required=false 不支持(强制要求 Bean 存在)
依赖 无需额外依赖 Spring 已内置,无需手动导入

举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import javax.inject.Inject;
import javax.inject.Named;
import org.springframework.stereotype.Service;

@Service
public class OrderService {
// 按类型注入 OrderRepository
@Inject
private OrderRepository orderRepository;

// 按名称注入:配合 @Named 指定 Bean 名称
@Inject
@Named("secondaryDataSource")
private DataSource dataSource;
}