一 自动注入@Autowire
代码实现:
package org.example.spring01.service;import org.springframework.stereotype.Service;@Service
public class UserService {}
package org.example.spring01.controller;import lombok.Data;
import lombok.ToString;
import org.example.spring01.bean.Person;
import org.example.spring01.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;import java.util.List;
import java.util.Map;@ToString
@Data
@Controller
public class UserController {/*** 自动注入 原理:Spring调用容器的getBean方法* @Autowired* 只有且只找到一个,直接注入,名字无所谓* 如果找到多个在按照名称去找,变量名就是名字*/@AutowiredUserService userService;@AutowiredList<Person> personList;@AutowiredMap<String,Person> personMap;}
package org.example.spring01;import org.example.spring01.controller.UserController;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;@SpringBootApplication
public class Spring01Application {public static void main(String[] args) {// 启动springboot应用ConfigurableApplicationContext ioc = SpringApplication.run(Spring01Application.class, args);System.out.println("run = " + ioc);UserController bean = ioc.getBean(UserController.class);System.out.println("bean = " + bean);}
}
二 默认首选/指定Bean@Primary @Qualifier
1 概述:
-
@Primary
:“默认选我”,简化多数场景的依赖注入。 -
@Qualifier
:“点名要谁”,精准控制依赖的选择。
2 当某个 Bean 被标记为
@Primary
,Spring 的依赖注入规则变为:
-
优先选择
@Primary
的 Bean,无论字段名如何变化。 -
忽略属性名匹配,直接注入
@Primary
标记的 Bean。
3 在没有
@Primary
时,Spring 按以下顺序解决依赖:
-
按类型匹配:寻找与字段类型一致的 Bean。
-
按名称匹配:如果有多个同类型 Bean,尝试将字段名与 Bean 的名称(ID)匹配。
@Primary标记一个Bean,然后在注入时用@Autowired,这时候会自动选择@Primary的;或者当有多个Bean时,用@Qualifier指定名称来注入。
当同时存在 @Primary
和 @Qualifier
时,@Qualifier
的优先级更高:
代码实现:
// @Primary默认组件,不说明Person具体就是这个@Primary@Bean("LiSi")public Person lisi() {Person person = new Person();person.setAge(18);person.setGender("男");person.setName("李四");return person;}
代码实现:
package org.example.spring01.service;import lombok.Data;
import org.example.spring01.bean.Person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;@Data // Lombok 注解,自动生成 getter/setter/toString 等方法
@Service // Spring 注解,标记为服务层 Bean
public class UserService {//如果容器中这种组件有多个,则使用@Qualifier注解精确指定注入的组件名@Qualifier("ZhangSan") // 指定注入名为 "ZhangSan" 的 Bean@Autowired // 自动注入依赖Person person; // 依赖的 Person 对象
}
三 自动注入@Resource
在选择使用哪一个注解时,可以根据项目的具体需求和个人偏好来决定。在许多情况下,这两种注解可以互换使用,特别是在只有一个符合条件的bean的情况下。
使用场景:
- 如果项目完全基于Spring框架,那么@Autowired可能是更自然的选择;
- 而如果是在Java EE环境中,或者你更倾向于通过名称来引用bean,那么@Resource可能更适合。
参数
- @Autowired 支持一个 required 参数,默认值为 true。设置为 false 时,表示即使没有找到对应的bean也不会报错。
- @Resource 支持 name 和 type 属性,可以明确指定要注入的bean的名称和类型。
注入方式
- @Autowired 支持构造器注入、设值方法注入以及字段注入。
- @Resource 主要用于字段注入和设值方法注入,不直接支持构造器注入。
四 构造器注入
在 Spring 框架中,构造器自动注入(Constructor Injection) 是一种通过类的构造方法(Constructor)自动注入依赖项的方式。它不仅是依赖注入(DI)的核心模式之一,更是 Spring 官方推荐的最佳实践。以下是其核心概念、优势及使用场景的详细解析:
1. 什么是构造器注入?
-
定义:通过类的构造方法参数传递依赖项,由 Spring 容器自动将匹配的 Bean 注入到参数中。
-
自动注入:从 Spring 4.3 开始,如果类只有一个构造方法,
@Autowired
注解可以省略,Spring 会默认使用该构造方法注入依赖。
@Service
public class UserService {private final UserRepository userRepository;private final EmailService emailService;// Spring 自动注入依赖(无需 @Autowired)public UserService(UserRepository userRepository, EmailService emailService) {this.userRepository = userRepository;this.emailService = emailService;}
}
2、构造器注入的优势
1. 依赖不可变性
-
final
字段:依赖项通过构造方法赋值后,可以声明为final
,确保对象初始化后不可变。 -
线程安全:避免依赖在运行时被意外修改,提升代码健壮性。
2. 明确依赖关系
-
强制依赖:构造方法参数明确声明了类的所有必需依赖,避免依赖缺失。
-
启动时检查:如果 Spring 容器中缺少某个依赖,应用会在启动时直接报错(而非运行时才暴露问题)。
3. 避免循环依赖
-
设计约束:如果两个类通过构造器注入相互依赖,Spring 会直接抛出
BeanCurrentlyInCreationException
,迫使开发者重构代码,解决循环依赖问题。
4. 更好的测试性
-
无需容器:在单元测试中,可以直接通过构造方法传入 Mock 对象,无需依赖 Spring 容器或反射。
-
代码透明:依赖关系一目了然,便于理解类的职责。
3、使用场景
1. 强依赖场景
-
类的核心功能依赖某个组件(如数据库访问层
UserRepository
)。 -
示例:服务类、控制器、数据访问对象(DAO)。
2. 需要不可变对象的场景
-
配置类、DTO(数据传输对象)、工具类等,确保依赖不会被修改。
3. Spring Boot 项目
-
Spring Boot 强烈推荐构造器注入,尤其是在结合 Lombok 的
@RequiredArgsConstructor
时,可以大幅简化代码。
4、实现方式
1. 隐式自动注入(Spring 4.3+)
-
如果类只有一个构造方法,Spring 会自动选择它进行注入,无需
@Autowired
。
@Service
public class PaymentService {private final PaymentGateway paymentGateway;// 无需 @Autowiredpublic PaymentService(PaymentGateway paymentGateway) {this.paymentGateway = paymentGateway;}
}
2. 显式指定构造方法
-
如果类有多个构造方法,需用
@Autowired
指定使用哪一个。
@Service
public class OrderService {private final InventoryService inventoryService;private final Logger logger;@Autowired // 显式标记要使用的构造方法public OrderService(InventoryService inventoryService) {this(inventoryService, LoggerFactory.getLogger(OrderService.class));}// 辅助构造方法public OrderService(InventoryService inventoryService, Logger logger) {this.inventoryService = inventoryService;this.logger = logger;}
}
3. 结合 Lombok 简化代码
-
使用
@RequiredArgsConstructor
自动生成包含final
字段的构造方法。
@Service
@RequiredArgsConstructor // 自动生成构造方法
public class NotificationService {private final EmailService emailService;private final SmsService smsService;
}