1.SpringBean依赖注入(DI)的方式有哪些?
1. 构造器注入 (Constructor Injection)
通过类的构造方法来注入依赖。Spring容器在创建Bean时,会调用其构造方法,并将所需的依赖作为参数传入。
-
优点:
- 不可变性 (Immutability) :依赖项通常被声明为
final,确保了它们在Bean的整个生命周期内不可变,避免了不可预料的修改,线程安全。 - 完全初始化的状态:对象在构造完成后,所有必需的依赖都已经就绪,状态是完整和一致的,避免了NPE(空指针异常)。
- 代码清晰,易于测试,可以直接在测试中通过
new来创建对象并传入mock依赖。
- 不可变性 (Immutability) :依赖项通常被声明为
2. Setter方法注入 (Setter Injection)
通过类的Setter方法进行注入。Spring容器在调用无参构造器或工厂方法创建Bean实例后,再调用对应的Setter方法来注入依赖。
-
代码示例:
@Service public class OrderService { private UserService userService; private ProductService productService; @Autowired public void setUserService(UserService userService) { this.userService = userService; } @Autowired public void setProductService(ProductService productService) { this.productService = productService; } } -
优点:
- 灵活性:允许在Bean创建后再改变依赖(尽管实践中很少这么做),更适合可选依赖的注入。
- 与传统的JavaBean规范兼容。
-
缺点:
- 对象在构造后可能处于不完整的状态(因为依赖可能还没被注入)。
- 无法将依赖项声明为
final。
3. 字段注入 (Field Injection)
直接在字段上使用 @Autowired 注解。这是最简洁但也是最不推荐的方式。
-
代码示例:
java
@Service public class OrderService { @Autowired private UserService userService; @Autowired private ProductService productService; }-
优点:
- 代码极其简洁,减少了大量的模板代码。
-
-
缺点:
- 不易测试:如果不使用Spring的测试框架,你无法直接通过
new来创建对象并初始化这些依赖,必须通过反射来注入mock对象,非常不方便。 - 隐藏了依赖关系:一个类到底依赖了什么,无法通过公共的接口(构造方法或Setter方法)清晰地看到,违反了“显式优于隐式”的原则。
- 无法声明为final:导致依赖可以被修改,破坏了不变性。
- 容易违反单一职责原则,因为可以很方便地注入很多依赖,导致类变得臃肿。
- 不易测试:如果不使用Spring的测试框架,你无法直接通过
2.Spring中常用的注解有哪些?
1. 核心配置与Bean声明注解
这些注解用于定义和配置Spring容器中的Bean。
-
@Configuration: 声明一个类为配置类,其内部会包含使用@Bean注解定义Bean的方法。它取代了传统的XML配置文件。 -
@ComponentScan: 配合@Configuration使用,用于自动扫描指定包路径下的组件(如@Component,@Service等),并将其注册为Bean。可配置扫描路径和过滤器。 -
@Bean: 在@Configuration类的方法上使用。它将方法的返回值定义为一个Bean,并交给Spring容器管理。常用于导入第三方库的类。 -
@Component: 一个通用的组件注解,表示一个类会被Spring自动扫描并创建为Bean。它是一个泛化的概念。 -
@Repository: 是@Component的特化,用于标注数据访问层(DAO层) 的类。其额外的一个作用是能够将平台特定的异常(如SQLException)转换为Spring的统一DataAccessException。 -
@Service: 是@Component的特化,用于标注业务服务层(Service层) 的类。主要用于逻辑上的区分,表明这个类持有业务逻辑。 -
@Controller/@RestController: 用于标注控制层(Web层) 的类。@Controller: 传统的Spring MVC控制器,通常返回一个视图名称。@RestController=@Controller+@ResponseBody。是RESTful Web服务的专用控制器,其所有方法返回的数据都会直接写入HTTP响应体,而不是视图名。这是开发API的首选注解。
-
@Autowired: 用于实现自动依赖注入。可以用在构造器、Setter方法、字段上。(如前一个问题所述,推荐用于构造器)。 -
@Qualifier: 当有多个相同类型的Bean时,用此注解来指定要注入的具体Bean的名称,与@Autowired配合使用,解决歧义性问题。 -
@Primary: 设置一个Bean为首选项。当有多个相同类型的Bean且没有指定@Qualifier时,优先注入被@Primary标注的Bean。 -
@Value: 用于注入外部属性值(如从application.properties文件),也可以注入SpEL表达式结果。@Value("${server.port}") private int port; @Value("#{systemProperties['user.home']}") private String userHome; -
@PropertySource/@PropertySources: 用于指定外部属性文件(如.properties)的位置,将其中的属性加载到Spring的Environment中,供@Value使用。@Configuration @PropertySource("classpath:app.properties") public class AppConfig { ... } -
@Scope: 指定Bean的作用域,如单例(singleton)、原型(prototype)、请求(request)、会话(session)等。@Bean @Scope("prototype") // 每次都会创建一个新的实例 public MyBean myBean() { return new MyBean(); }
2. Web MVC相关注解
这些注解主要用于处理Web请求。
-
@RequestMapping: 一个通用的请求映射注解,可以指定URL路径、HTTP方法(GET, POST等)。通常用其变体:@GetMapping: 等价于@RequestMapping(method = RequestMethod.GET)@PostMapping@PutMapping@DeleteMapping@PatchMapping
-
@RequestParam: 用于从请求参数中提取值。public String getUser(@RequestParam("id") Long userId) { ... } -
@PathVariable: 用于从URL模板变量中提取值。@GetMapping("/users/{id}") public String getUser(@PathVariable("id") Long userId) { ... } -
@RequestBody: 将HTTP请求体(通常是JSON)反序列化为一个Java对象。@PostMapping("/users") public User createUser(@RequestBody User user) { ... } -
@ResponseBody: 将方法的返回值直接序列化后写入HTTP响应体(如返回JSON)。@RestController已经默认包含了它。 -
@ModelAttribute: 用于将请求参数绑定到模型对象,常用于表单处理。也可以用于在方法上,表示该方法会在控制器每个方法执行前被调用,用于准备模型数据。 -
@ExceptionHandler: 在控制器内部定义一个处理特定异常的方法,用于做局部的异常处理。 -
@ControllerAdvice/@RestControllerAdvice: 定义一个全局的异常处理、数据绑定、数据初始化的类。可以看作是全局的@ExceptionHandler,能够处理所有控制器抛出的异常。
3. 事务管理注解
-
@Transactional: 声明一个方法或类需要事务管理。这是Spring声明式事务管理的核心注解。可以配置事务的传播行为、隔离级别、超时时间、回滚条件等。@Transactional public void transferMoney(Long fromId, Long toId, BigDecimal amount) { // ... 业务逻辑 }
4. 测试相关注解
@SpringBootTest: 用于Spring Boot应用的集成测试,它会加载完整的应用程序上下文。@DataJpaTest,@WebMvcTest,@JsonTest等:用于切片测试(Slice Test) ,只加载应用程序的特定部分,使得测试更快、更专注。@MockBean: 在测试环境中,向Spring容器中添加一个Mockito mock对象,以替换掉原有的Bean,用于隔离测试。