Spring IoC 注解式开发全解析
在 Spring 框架的开发中,依赖注入(DI)和控制反转(IoC)是核心设计思想。早期的 XML 配置方式虽然强大,但随着项目规模扩大,配置文件会变得冗长复杂。Spring 从 2.5 版本开始引入注解式开发,通过简洁的注解实现 Bean 的定义和依赖注入,极大提升了开发效率。本文将系统讲解 Spring IoC 注解式开发的核心知识点,每个章节都配备完整的代码示例,帮助读者快速掌握实战技巧。
一、基础注解:Bean 定义与扫描
1. @Component及其衍生注解
作用:标记类为 Spring 管理的 Bean,替代 XML 中的<bean>标签衍生注解:
- @Repository:标记数据访问层组件(DAO)
- @Service:标记业务逻辑层组件(Service)
- @Controller:标记表现层组件(Controller)
- @RestController:Spring Boot 中用于 RESTful 接口的组合注解(@Controller+@ResponseBody)
代码示例:
// DAO层
@Repository
public class UserDao {public void save() {System.out.println("UserDao save");}
}// Service层
@Service
public class UserService {private UserDao userDao;// 依赖注入(后文详解)public UserService(UserDao userDao) {this.userDao = userDao;}public void register() {userDao.save();}
}// Web层
@RestController
@RequestMapping("/users")
public class UserController {private final UserService userService;// 构造函数注入public UserController(UserService userService) {this.userService = userService;}@GetMapping("/register")public String register() {userService.register();return "Register success";}
}
⑴. @RestController
此注解是 Spring 4.0 引入的,它是 @Controller
和 @ResponseBody
的组合注解。
@Controller
:该注解属于 Spring MVC 框架,用于把一个类标记为 Spring MVC 的控制器。控制器负责处理客户端的请求,然后返回相应的视图或者数据。@ResponseBody
:这个注解会让控制器方法返回的对象直接以 HTTP 响应体的形式返回,而不是解析为视图名称。
把 @RestController
加在类上,意味着这个类是一个 RESTful 风格的控制器,它的方法返回的对象会被自动序列化为 JSON 或者 XML 格式的数据,然后作为 HTTP 响应体返回给客户端。
⑵. @RequestMapping("/users")
@RequestMapping
注解能够把 HTTP 请求映射到控制器的处理方法上。它可以在类级别或者方法级别使用。
- 类级别:在类上使用
@RequestMapping("/users")
,意味着这个控制器里所有处理方法的 URL 都会以/users
作为前缀。 - 方法级别:如果在方法上使用
@RequestMapping
,则该方法的完整 URL 是类级别的 URL 前缀和方法级别的 URL 组合而成。
⑶. @GetMapping("/register")
@GetMapping
是 @RequestMapping
的一种快捷方式,专门用于处理 HTTP GET 请求。
- 等价关系:
@GetMapping("/register")
等同于@RequestMapping(method = RequestMethod.GET, value = "/register")
。 - 作用:在控制器方法上使用
@GetMapping("/register")
,表示这个方法会处理以/users/register
为 URL 的 HTTP GET 请求(因为类上有@RequestMapping("/users")
)。
2. @ComponentScan
作用:指定 Spring 扫描 Bean 的包路径,替代 XML 中的<context:component-scan>使用方式:
- XML 配置:<context:component-scan base-package="com.example"/>
- Java 配置类:@ComponentScan("com.example")或@ComponentScan(basePackages = "com.example")
Java 配置类示例:
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;@Configuration
@ComponentScan("com.example") // 扫描com.example包及其子包
public class AppConfig {
}
二、依赖注入注解:实现 Bean 关联
1. @Autowired(按类型注入)
作用:自动装配 Bean,默认按类型匹配支持场景:构造函数、字段、Setter 方法注意:Spring 4.3 + 后,构造函数注入可省略@Autowired(单构造函数场景)
字段注入示例:
@Service
public class UserService {@Autowired // 按类型注入UserDaoprivate UserDao userDao;// 使用userDao...
}
构造函数注入示例:
@Service
public class UserService {private final UserDao userDao;// 单构造函数时@Autowired可省略@Autowired public UserService(UserDao userDao) {this.userDao = userDao;}
}
2. @Qualifier(按名称注入)
作用:与@Autowired配合,解决同类型多个 Bean 的注入歧义使用方式:通过@Qualifier("beanName")指定具体 Bean
场景:当存在多个UserDao实现类时
// 定义两个实现类
@Repository("mysqlUserDao")
public class MysqlUserDao implements UserDao { /* ... */ }@Repository("oracleUserDao")
public class OracleUserDao implements UserDao { /* ... */ }// 注入时指定名称
@Service
public class UserService {@Autowired@Qualifier("mysqlUserDao") // 指定注入mysqlUserDaoprivate UserDao userDao;
}
3. @Resource(JSR-250 标准注解)
作用:支持按名称(name属性)或类型(type属性)注入默认规则:优先按名称匹配,无匹配时按类型对比:Spring 原生@Autowired按类型,@Resource是 Java 标准注解
示例:
@Service
public class UserService {@Resource(name = "mysqlUserDao") // 显式指定Bean名称private UserDao userDao;// 或 @Resource(type = MysqlUserDao.class) 按类型注入
}
4. @Value(注入基本类型 / 字符串)
作用:注入配置文件中的属性值或直接量支持场景:注入String、基本类型、表达式(${})、SpEL(#{})
示例:
// 注入配置文件中的值(application.properties)
@Value("${app.version}") // 读取配置项
private String appVersion;@Value("${server.port}")
private int port;// 注入直接量
@Value("Hello World")
private String welcomeMsg;// 注入SpEL表达式
@Value("#{T(java.lang.Math).random() * 100}") // 生成0-100的随机数
private double randomNum;
三、高级注解:Bean 定义与生命周期
1. @Scope(Bean 作用域)
作用:指定 Bean 的作用域,替代 XML 中的scope属性支持值:singleton(默认)、prototype、request、session、application(Servlet 环境)
示例:
@Service
@Scope("prototype") // 每次获取创建新实例
public class UserService { /* ... */ }
2. 生命周期注解
@PostConstruct(初始化方法)
作用:标记 Bean 初始化完成后执行的方法,替代init-method要求:方法无参数,返回值为void,最多一个
@Service
public class UserService {@PostConstructpublic void init() {System.out.println("UserService initialized");}
}
@PreDestroy(销毁前方法)
作用:标记 Bean 销毁前执行的方法,替代destroy-method适用场景:释放资源(如关闭数据库连接)
@Service
public class UserService {@PreDestroypublic void destroy() {System.out.println("UserService destroyed");}
}
3. Java 配置类注解(替代 XML 配置)
@Configuration
作用:标记类为配置类,替代 XML 根标签<beans>
@Bean
作用:定义 Bean,替代 XML 中的<bean>标签
@Import
作用:导入其他配置类,替代 XML 中的<import>
Java 配置类示例:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;@Configuration
@Import(DataSourceConfig.class) // 导入其他配置类
public class AppConfig {@Bean("myBean") // 定义名为myBean的Beanpublic MyBean createMyBean() {return new MyBean();}
}// 独立配置类
@Configuration
public class DataSourceConfig {@Beanpublic DataSource dataSource() {// 配置数据源...return new HikariDataSource();}
}
五、注解开发最佳实践
1.分层使用注解:
- @Controller/@RestController用于 Web 层
- @Service用于业务层
- @Repository用于数据访问层
- 避免在工具类 / 实体类中使用组件注解
2.依赖注入策略:
- 构造函数注入:用于注入必需依赖(建议使用final修饰)
- Setter 方法注入:用于可选依赖
- 字段注入:简化代码(但不利于单元测试,谨慎使用)
3.混合配置:
- 推荐使用 Java 配置类(@Configuration+@Bean)替代 XML
- 遗留项目可混合使用注解和 XML,但建议逐步迁移至全注解
4.处理循环依赖:
- 构造函数注入会导致循环依赖报错,改用 Setter 注入或@Lazy注解
- Spring 默认解决单例 Bean 的 Setter 注入循环依赖(通过提前暴露代理对象)
六、总结
Spring 注解式开发通过简洁的语法实现了强大的 IoC 功能,显著减少了样板代码,让开发者更专注于业务逻辑。本文覆盖了从基础 Bean 定义到高级生命周期管理的核心注解,每个知识点均配备可运行的代码示例。实际项目中,建议结合 Spring Boot 进一步简化配置(自动扫描、默认配置),并根据团队技术栈选择 XML、Java 配置类或纯注解的开发方式。
掌握这些注解后,开发者可以更高效地构建松耦合的企业级应用,同时利用 Spring 生态(如 Spring MVC、Spring Data)实现快速开发。后续可以深入学习 Spring Boot 的自动配置原理,进一步提升微服务开发能力。