1. Bean定义基础
1.1 什么是Bean定义(BeanDefinition)
Bean定义是Spring IoC容器中用于描述Bean的元数据对象,它是Bean实例化的蓝图。
// Bean定义包含的核心信息
public interface BeanDefinition {
String getBeanClassName(); // 类的全限定名
String getScope(); // 作用域(singleton/prototype等)
boolean isLazyInit(); // 是否延迟初始化
String[ ] getDependsOn(); // 依赖的其他Bean
boolean isAutowireCandidate(); // 是否作为自动装配候选
boolean isPrimary(); // 是否为主候选Bean
String getInitMethodName(); // 初始化方法名
String getDestroyMethodName(); // 销毁方法名
// ... 更多属性
}
1.2 Bean定义 vs Bean实例
| 特性 | Bean定义(BeanDefinition) | Bean实例(Bean Instance) |
|---|---|---|
| 性质 | 元数据/配置信息 | 实际的Java对象 |
| 创建时机 | 容器启动时(配置加载阶段) | 根据作用域决定 |
| 存储位置 | BeanDefinitionRegistry | BeanFactory/ApplicationContext |
| 数量 | 每个Bean一个定义 | 根据作用域可能有多个实例 |
| 作用 | 描述如何创建Bean | 提供实际的业务功能 |
// 简化示意
ApplicationContext context = new AnnotationConfigApplicationContext();
// 阶段1:注册Bean定义
BeanDefinition definition = new RootBeanDefinition(OrderService.class);
definition.setScope("singleton");
context.registerBeanDefinition("orderService", definition);
// 阶段2:根据Bean定义创建Bean实例
OrderService instance = context.getBean(OrderService.class);
1.3 Bean定义的创建方式
方式1:注解扫描(最常用)
@Configuration
@ComponentScan("com.xxx.mall")
public class AppConfig {
// 扫描包下所有@Component/@Service/@Controller等
// 自动创建BeanDefinition
}
@Service // 被扫描器识别,自动注册为BeanDefinition
public class OrderService { }
方式2:@Bean方法
@Configuration
public class AppConfig {
@Bean // 方法返回值类型和名称用于创建BeanDefinition
public DataSource dataSource() {
HikariDataSource ds = new HikariDataSource();
ds.setJdbcUrl("jdbc:mysql://localhost:3306/db");
return ds;
}
}
方式3:XML配置(传统方式)
<beans>
<bean id="orderService" class="com.xxx.OrderService"
scope="singleton" lazy-init="false">
<property name="orderRepository" ref="orderRepository"/>
</bean>
</beans>
方式4:编程式注册
public class CustomBeanRegistrar {
public void register(BeanDefinitionRegistry registry) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(OrderService.class)
.setScope("singleton")
.setLazyInit(false);
registry.registerBeanDefinition("orderService",
builder.getBeanDefinition());
}
}
1.4 Bean的完整生命周期
1. 加载Bean定义
↓
2. 实例化Bean(调用构造器)
↓
3. 填充属性(依赖注入)
↓
4. 调用Aware接口方法
- BeanNameAware.setBeanName()
- BeanFactoryAware.setBeanFactory()
- ApplicationContextAware.setApplicationContext()
↓
5. BeanPostProcessor.postProcessBeforeInitialization()
↓
6. 调用初始化方法
- @PostConstruct注解的方法
- InitializingBean.afterPropertiesSet()
- 自定义init-method
↓
7. BeanPostProcessor.postProcessAfterInitialization()
↓
8. Bean就绪,可以使用
↓
9. 容器关闭时调用销毁方法
- @PreDestroy注解的方法
- DisposableBean.destroy()
- 自定义destroy-method
实际代码示例:
@Service
public class OrderService implements InitializingBean, DisposableBean {
private OrderRepository orderRepository;
// 1. 构造器(实例化阶段)
public OrderService() {
System.out.println("1. 构造器调用");
}
// 2. 依赖注入(属性填充阶段)
@Autowired
public void setOrderRepository(OrderRepository orderRepository) {
System.out.println("2. 注入依赖");
this.orderRepository = orderRepository;
}
// 3. 初始化方法
@PostConstruct
public void init() {
System.out.println("3. @PostConstruct初始化");
}
@Override
public void afterPropertiesSet() {
System.out.println("4. afterPropertiesSet初始化");
}
// 4. 销毁方法
@PreDestroy
public void cleanup() {
System.out.println("5. @PreDestroy清理");
}
@Override
public void destroy() {
System.out.println("6. destroy清理");
}
}
// 输出顺序:
// 1. 构造器调用
// 2. 注入依赖
// 3. @PostConstruct初始化
// 4. afterPropertiesSet初始化
// (容器关闭时)
// 5. @PreDestroy清理
// 6. destroy清理
1.5 Bean定义的后置处理
Spring允许在Bean定义注册后、实例化前修改Bean定义:
@Component
public class CustomBeanDefinitionPostProcessor
implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) {
// 获取Bean定义
BeanDefinition definition = beanFactory
.getBeanDefinition("orderService");
// 修改Bean定义属性
definition.setScope("prototype"); // 改为原型模式
definition.setLazyInit(true); // 改为延迟初始化
}
}
2. 核心注解实现原理
2.1 依赖注入类
@Autowired
-
实现机制: Spring容器启动时通过
AutowiredAnnotationBeanPostProcessor处理 -
工作流程:
-
容器启动时扫描所有Bean定义
-
反射获取标注@Autowired的字段/构造器/方法
-
根据类型从容器中查找匹配的Bean
-
通过反射设置字段值或调用方法完成注入
-
@Component
-
角色: Spring组件注解的基础注解,标记类为Spring管理的Bean
-
实现机制: 通过
ClassPathBeanDefinitionScanner组件扫描 -
工作流程:
-
Spring容器启动时扫描指定包路径
-
识别标注了@Component及其派生注解的类
-
将类信息注册为BeanDefinition
-
根据BeanDefinition创建Bean实例并放入IoC容器
-
派生注解体系:
@Component // 基础注解,通用组件
├─ @Service // 业务逻辑层
├─ @Repository // 数据访问层
└─ @Controller // 控制层
└─ @RestController // RESTful控制层
注解对比:
| 注解 | 语义层次 | 使用场景 | 额外功能 |
|---|---|---|---|
| @Component | 通用组件 | 不属于明确分层的工具类、配置类 | 无 |
| @Service | 业务层 | Service层,处理业务逻辑 | 无(语义化) |
| @Repository | 持久层 | DAO/Repository层,数据访问 | 自动转换持久化异常 |
| @Controller | 控制层 | MVC控制器 | 配合@RequestMapping |
| @RestController | RESTful层 | RESTful API控制器 | @Controller + @ResponseBody |
@Component典型使用场景:
// 1. 工具类组件
@Component
public class RedisUtil {
public void set(String key, Object value) { }
}
// 2. 配置类(也可用@Configuration)
@Component
public class AppConfigProperties {
private String appName;
private String version;
}
// 3. 事件监听器
@Component
public class OrderEventListener {
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) { }
}
// 4. 定时任务
@Component
public class ScheduledTasks {
@Scheduled(cron = "0 0 1 * * ?")
public void cleanupTask() { }
}
// 5. 消息监听器
@Component
public class MessageConsumer {
@RabbitListener(queues = "orderQueue")
public void processMessage(String message) { }
}
为什么要用派生注解而非@Component:
-
语义化: 清晰表达类的职责和分层
-
AOP增强: 某些注解有额外功能(如@Repository的异常转换)
-
可读性: 代码更易理解和维护
-
工具支持: IDE和框架能根据注解提供针对性支持
// ❌ 不推荐:语义不清晰
@Component
public class OrderService { }
// ✅ 推荐:明确表达是业务层
@Service
public class OrderService { }
// ❌ 不推荐:语义不清晰
@Component
public class OrderRepository { }
// ✅ 推荐:明确表达是持久层,且有异常转换功能
@Repository
public class OrderRepository { }
2.2 Web层类
@RestController
-
组合注解:
@Controller+@ResponseBody -
功能:
-
标记为Spring MVC控制器
-
自动将返回值序列化为JSON/XML响应
-
@RequestMapping
-
实现机制:
RequestMappingHandlerMapping处理 -
工作流程:
-
扫描所有@Controller/@RestController类
-
解析@RequestMapping注解信息(路径、HTTP方法等)
-
建立URL到处理方法的映射关系
-
请求到达时,DispatcherServlet根据映射分发到对应方法
-
@Validated
-
实现机制: 基于JSR-303/JSR-380 Bean Validation规范
-
工作流程:
-
MethodValidationPostProcessor创建AOP代理 -
方法调用前拦截,触发参数校验
-
校验失败抛出
ConstraintViolationException
-
2.3 文档类
@Api / @ApiOperation
-
框架: Swagger/OpenAPI
-
实现机制:
-
启动时扫描注解通过反射提取元数据
-
生成API文档JSON描述
-
Swagger UI渲染为可视化文档
-
3. 注解必要性与使用场景
| 注解 | 必要性 | 使用场景 | 替代方案 |
|---|---|---|---|
| @Autowired | ⭐⭐⭐⭐⭐ | 注入Service/Repository/Component | 构造器注入、@Resource |
| @Service | ⭐⭐⭐⭐⭐ | 标记业务逻辑层 | @Component |
| @RestController | ⭐⭐⭐⭐⭐ | RESTful API控制器 | @Controller + @ResponseBody |
| @RequestMapping | ⭐⭐⭐⭐⭐ | 定义API路由 | @GetMapping/@PostMapping等 |
| @Validated | ⭐⭐⭐ | 需要参数校验 | 手动校验 |
| @Api | ⭐⭐ | 生成API文档 | 手写文档 |
典型使用场景
// Service层
@Service
public class OrderService {
private final OrderRepository orderRepository;
// 构造器注入(推荐)
public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
}
// Controller层
@RestController
@RequestMapping("/api/v1.0/orders")
@Validated
@Api(tags = "订单管理")
public class OrderController {
private final OrderService orderService;
public OrderController(OrderService orderService) {
this.orderService = orderService;
}
@PostMapping
@ApiOperation("创建订单")
public Response create(@Valid @RequestBody OrderDTO dto) {
return Response.success(orderService.create(dto));
}
}
4. 开发最佳实践
4.1 @Autowired 使用建议
✅ 推荐:构造器注入
@Service
public class OrderService {
private final PaymentService paymentService;
private final InventoryService inventoryService;
// 单构造器可省略@Autowired
public OrderService(PaymentService paymentService,
InventoryService inventoryService) {
this.paymentService = paymentService;
this.inventoryService = inventoryService;
}
}
优势:
-
字段可以声明为final,保证不可变性
-
便于单元测试(直接new对象传入mock依赖)
-
强制所有必需依赖在对象创建时就绪
-
避免NullPointerException
❌ 不推荐:字段注入
@Service
public class OrderService {
@Autowired
private PaymentService paymentService; // 无法final
}
问题:
-
无法保证不可变性
-
隐藏依赖关系
-
单元测试需要Spring容器或反射
注意事项
-
避免循环依赖(使用
@Lazy或重构设计) -
注入接口而非实现类
-
多个同类型Bean时使用
@Qualifier指定
4.2 @Component及其派生注解使用建议
选择合适的注解
// ✅ 业务逻辑层使用@Service
@Service
public class OrderService {
public Order createOrder(OrderDTO dto) { }
public Order getOrder(Long id) { }
}
// ✅ 数据访问层使用@Repository
@Repository
public class OrderRepository {
public Order findById(Long id) { }
}
// ✅ 不属于明确分层的使用@Component
@Component
public class JwtTokenUtil {
public String generateToken(String username) { }
public boolean validateToken(String token) { }
}
// ✅ 配置属性类
@Component
@ConfigurationProperties(prefix = "app")
public class AppProperties {
private String name;
private String version;
}
// ❌ 职责混乱
@Service
public class BusinessService {
// 包含订单、支付、物流等多种业务 - 违反单一职责
}
// ❌ 注解选择错误
@Component // 应该用@Service
public class PaymentService { }
@Service // 应该用@Repository
public class UserDao { }
Bean命名规范
// 默认Bean名称为首字母小写的类名
@Component // Bean名称: "orderValidator"
public class OrderValidator { }
// 自定义Bean名称
@Component("customOrderValidator")
public class OrderValidator { }
// 多实现时明确命名
@Service("alipayPaymentService")
public class AlipayPaymentService implements PaymentService { }
@Service("wechatPaymentService")
public class WechatPaymentService implements PaymentService { }
注意事项
规范:
-
✅ 遵循单一职责原则
-
✅ 按业务领域划分Service
-
✅ 根据分层选择合适的注解(@Service/@Repository/@Component)
-
✅ 工具类、辅助类使用@Component
-
❌ 避免在一个类上同时使用多个组件注解
-
❌ 避免过度使用@Component,优先使用语义化的派生注解
-
❌ 不要在接口上使用组件注解(注解应在实现类上)
// ❌ 错误:在接口上使用
@Service
public interface PaymentService { }
// ✅ 正确:在实现类上使用
public interface PaymentService { }
@Service
public class AlipayPaymentServiceImpl implements PaymentService { }
4.3 @RequestMapping 使用建议
// ✅ RESTful风格
@RestController
@RequestMapping("/api/v1.0/orders")
public class OrderController {
@GetMapping("/{id}") // GET /api/v1.0/orders/123
public Response get(@PathVariable Long id) { }
@PostMapping // POST /api/v1.0/orders
public Response create(@RequestBody OrderDTO dto) { }
@PutMapping("/{id}") // PUT /api/v1.0/orders/123
public Response update(@PathVariable Long id, @RequestBody OrderDTO dto) { }
@DeleteMapping("/{id}") // DELETE /api/v1.0/orders/123
public Response delete(@PathVariable Long id) { }
}
规范:
-
类级别定义公共前缀
-
使用HTTP方法明确语义(@GetMapping、@PostMapping等)
-
路径使用小写和连字符
-
版本号放在路径中(/v1.0/)
4.4 @Validated 使用建议
@RestController
@Validated // 类级别开启校验
public class OrderController {
@PostMapping("/orders")
public Response create(@Valid @RequestBody OrderDTO dto) {
// @Valid触发DTO内部校验
return Response.success();
}
@GetMapping("/orders/{id}")
public Response get(@PathVariable @Min(1) Long id) {
// @Validated + @Min校验路径参数
return Response.success();
}
}
// DTO定义
@Data
public class OrderDTO {
@NotNull(message = "订单号不能为空")
private String orderNo;
@Min(value = 1, message = "金额必须大于0")
private BigDecimal amount;
@Email(message = "邮箱格式不正确")
private String email;
}
配合全局异常处理:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public Response handleValidationException(MethodArgumentNotValidException e) {
String message = e.getBindingResult().getFieldErrors()
.stream()
.map(FieldError::getDefaultMessage)
.collect(Collectors.joining(", "));
return Response.fail(message);
}
}
5. Bean作用域与线程安全
5.1 单例模式(默认)
@Service // 默认singleton作用域
public class OrderService {
// 这是全局单例,所有请求共享同一实例
}
// 等同于
@Service
@Scope("singleton")
public class OrderService { }
5.2 原型模式
@Service
@Scope("prototype") // 每次注入创建新实例
public class ReportGenerator {
// 适用于有状态的Bean
}
5.3 线程安全问题
❌ 错误:单例Bean使用实例变量
@Service
public class OrderService {
private Order currentOrder; // 危险!多线程会互相覆盖
public void process(Long orderId) {
this.currentOrder = orderRepository.findById(orderId);
// 高并发下currentOrder会被其他线程覆盖
}
}
✅ 正确:使用方法参数传递状态
@Service
public class OrderService {
// 无状态,线程安全
public void process(Long orderId) {
Order order = orderRepository.findById(orderId); // 局部变量
// 每次调用独立,线程安全
}
}
✅ 正确:使用ThreadLocal(谨慎)
@Service
public class UserContextService {
private ThreadLocal<User> currentUser = new ThreadLocal<>();
public void setCurrentUser(User user) {
currentUser.set(user);
}
public User getCurrentUser() {
return currentUser.get();
}
public void clear() {
currentUser.remove(); // 记得清理,避免内存泄漏
}
}
5.4 Controller和Service都是单例
@RestController
public class OrderController {
private final OrderService orderService; // 指向同一个单例Service
public OrderController(OrderService orderService) {
this.orderService = orderService;
}
// 每个HTTP请求由不同线程处理
// 但都使用同一个Controller实例和同一个OrderService实例
}
关键点:
-
Controller、Service、Repository默认都是单例
-
多个请求并发访问同一个实例
-
必须保证无状态或线程安全
6. 常见问题与解决方案
6.1 循环依赖
// ❌ 循环依赖
@Service
public class OrderService {
@Autowired
private PaymentService paymentService;
}
@Service
public class PaymentService {
@Autowired
private OrderService orderService; // 循环!
}
解决方案:
-
使用@Lazy延迟加载
@Service public class OrderService { private final PaymentService paymentService; public OrderService(@Lazy PaymentService paymentService) { this.paymentService = paymentService; } } -
重构设计(推荐)
// 提取公共依赖
@Service
public class OrderService {
private final OrderRepository orderRepository;
}
@Service
public class PaymentService {
private final PaymentRepository paymentRepository;
}
@Service
public class OrderPaymentFacade {
private final OrderService orderService;
private final PaymentService paymentService;
public void processOrderPayment() {
// 协调两个服务
}
}
6.2 多个同类型Bean
@Service("alipayService")
public class AlipayService implements PaymentService { }
@Service("wechatService")
public class WechatPayService implements PaymentService { }
// 注入时指定
@Autowired
@Qualifier("alipayService")
private PaymentService paymentService;
6.3 可选依赖
@Autowired(required = false)
private OptionalService optionalService; // 可能为null
// 或使用Optional
@Autowired
private Optional<OptionalService> optionalService;
7. 总结
核心原则
-
优先构造器注入,保证不可变性和可测试性
-
保持Bean无状态,避免线程安全问题
-
遵循单一职责,合理划分Service边界
-
统一路径规范,使用RESTful风格
-
充分利用校验,参数验证前移
性能考虑
-
单例Bean在应用启动时创建,运行时复用,性能最优
-
避免过度使用prototype作用域
-
合理使用@Lazy延迟初始化,加快启动速度
可维护性
-
注解让配置更接近代码,降低维护成本
-
但避免过度使用注解,保持代码简洁
-
重要的配置信息建议集中管理(如application.properties)