Spring(三)容器-注入

一 自动注入@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 的依赖注入规则变为:

  1. 优先选择 @Primary 的 Bean,无论字段名如何变化。

  2. 忽略属性名匹配,直接注入 @Primary 标记的 Bean。

3 在没有 @Primary 时,Spring 按以下顺序解决依赖:

  1. 按类型匹配:寻找与字段类型一致的 Bean。

  2. 按名称匹配:如果有多个同类型 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;
}

补充:

五 感知接口 xxxAware

什么时候需要用 Aware?

  • 需要直接操作容器时(比如动态获取 Bean)

  • 需要获取 Bean 的元信息(如 Bean 的名称)

  • 需要访问底层资源(如环境变量、资源文件)

实际开发建议

  1. 优先使用依赖注入@Autowired),避免滥用 Aware

  2. 典型场景

    • 框架扩展开发(如自定义 Starter)

    • 动态加载配置文件

    • 实现特殊初始化逻辑(需容器配合)

代码对比示例

用 @Autowired(推荐):

@Component
public class MyService {@Autowired // 让 Spring 自动注入private ApplicationContext context;
}

用 ApplicationContextAware

@Component
public class MyService implements ApplicationContextAware {private ApplicationContext context;@Override // Spring 自动调用public void setApplicationContext(ApplicationContext ctx) {this.context = ctx;}
}

代码实现:

package org.example.spring01.service;import lombok.Data;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;@Data
@Service
public class hahaService implements EnvironmentAware {private Environment environment;@Overridepublic void setEnvironment(Environment environment) {this.environment = environment;}public String getOsType() {return environment.getProperty("OS");}}

调用

    public static void main(String[] args) {// 启动springboot应用ConfigurableApplicationContext ioc = SpringApplication.run(Spring01Application.class, args);hahaService bean = ioc.getBean(hahaService.class);System.out.println("bean = " + bean);String osType = bean.getOsType();System.out.println("osType = " + osType);}

六 给属性赋值@Value

@Value 的本质

它就像一把 配置钥匙,让 Spring 能把外部的配置值(如配置文件、环境变量等)直接注入到类的字段中,无需手动读取文件。

代码实现:

package org.example.spring01.bean;import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Data
@Component
public class Dog {/*** 1 @Value("字面值):直接赋值* 2 @Value("${dog.age}"),动态从配置文件中取出某一项的值,需要先在配置文件中配置好对应的值* 3 @Value("#{SpEL}"), SpEL表达式,Spring Expression Language,Spring 表达式语言,可以获取 Bean 的属性,调用方法,运算符等*/@Value("大黄")private String name;@Value("${dog.age}")private int age;@Value("雄性")private String gender;@Value("#{10*3}")private Integer weight;//实现构造器注入public Dog() {}}

具体调用:

    public static void main(String[] args) {// 启动springboot应用ConfigurableApplicationContext ioc = SpringApplication.run(Spring01Application.class, args);Object da = ioc.getBean(Dog.class);System.out.println("大黄 = " + da);}

图片展示

七 加载外部配置文件@PropertySource

@PropertySource 的主要作用是将外部配置文件中的属性加载到 Spring 的 Environment 中,从而可以在应用中使用这些属性。

代码实现:

@Service
@PropertySource("classpath:Cat.properties")
public class Cat {private final String name;private final int age;public Cat(@Value("${cat.name:mimi}") String name, @Value("${cat.age}") int age) {this.name = name;this.age = age;}// 仅提供 getter 方法public String getName() {return name;}public int getAge() {return age;}
}
  • 依赖通过构造器参数传入
    所有依赖项(name 和 age)都是通过构造器的参数传入的,而不是通过 Setter 方法或字段直接注入。

  • Spring 自动调用构造器
    当 Spring 创建 Cat 的 Bean 时,会自动调用这个构造器,并将配置值作为参数传入。

    public static void main(String[] args) {// 启动springboot应用ConfigurableApplicationContext ioc = SpringApplication.run(Spring01Application.class, args);Dog da = ioc.getBean(Dog.class);System.out.println("大黄 = " + da);Cat x = ioc.getBean(Cat.class);System.out.println("x = " + x.getName()+ " " + x.getAge());}

八 多环境@profile

@Profile 注解是 Spring Framework 提供的一个工具,它允许开发者根据不同的运行环境(如开发、测试、生产等)来控制 Bean 的创建和加载。它的主要目的是支持多环境配置,使得应用程序可以根据当前激活的 profile 来动态地选择合适的配置或组件。

代码实现:

1 定义一个基础类

package org.example.spring01.dataSource;import lombok.Data;@Data
public class MyDataSource {private String url;private String username;private String password;}

2 配置类,用于定义不同环境下的数据源

package org.example.spring01.config;import org.example.spring01.dataSource.MyDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;@Configuration
public class DataSourceConfig {@Profile({"dev","default"})@Beanpublic MyDataSource dev() {MyDataSource myDataSource = new MyDataSource();myDataSource.setUrl("jdbc:mysql://localhost:3306/dev");myDataSource.setUsername("root_dev");myDataSource.setPassword("123456");return myDataSource;}@Profile("test")@Beanpublic MyDataSource test() {MyDataSource myDataSource = new MyDataSource();myDataSource.setUrl("jdbc:mysql://localhost:3306/test");myDataSource.setUsername("root_test");myDataSource.setPassword("123456");return myDataSource;}@Profile("prod")@Beanpublic MyDataSource prod() {MyDataSource myDataSource = new MyDataSource();myDataSource.setUrl("jdbc:mysql://localhost:3306/prod");myDataSource.setUsername("root_prod");myDataSource.setPassword("123456");return myDataSource;}}

3 使用构造函数注入的方式获取MyDataSource实例

package org.example.spring01.dao;import org.example.spring01.dataSource.MyDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
public class DeliverDao {private final MyDataSource myDataSource;public DeliverDao(MyDataSource myDataSource) {this.myDataSource = myDataSource;}public void deliver() {System.out.println("数据源:保存数据" + myDataSource);}
}

4 启动Spring Boot应用程序,运行Spring01Application类

    public static void main(String[] args) {ConfigurableApplicationContext ioc = SpringApplication.run(Spring01Application.class, args);DeliverDao bean = ioc.getBean(DeliverDao.class);bean.deliver();}

5 配置类

6 运行样式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/28841.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL零基础教程16—表连接进阶

复习表别名 之前已经学习过&#xff0c;查询的时候可以使用as来对检索的列进行重命名&#xff0c;这样可以让sql更加简介&#xff0c;增强易读性&#xff08;as可以省略&#xff09; 此外&#xff0c;使用表别名还可以支持在一条select语句中&#xff0c;一个表是被多次使用 …

【MySQL】MySQL 复制

MySQL复制介绍 MySQL复制允许将主实例(master)上的数据同步到一个或多个从实例(slave)上&#xff0c;默认情况下复制是异步进行的&#xff0c;从库也不需要一直连接到主库来同步数据。 MySQL复制的数据粒度可以是主实例上所有的数据库&#xff0c;也可以是指定的一个或多个数据…

Linux的缓存I/O和无缓存IO

一、I/O缓存的背景 I/O缓存是指在内存里开辟一块区域&#xff0c;存放用来接收用户输入和用于计算机输出的数据&#xff0c;以减小系统开销和提高外设效率。linux对IO文件的操作分为不带缓存的IO操作和带缓存的IO操作&#xff08;标准IO操作&#xff09;。为什么存在C标准I/O库…

YOLOv5 + SE注意力机制:提升目标检测性能的实践

一、引言 目标检测是计算机视觉领域的一个重要任务&#xff0c;广泛应用于自动驾驶、安防监控、工业检测等领域。YOLOv5作为YOLO系列的最新版本&#xff0c;以其高效性和准确性在实际应用中表现出色。然而&#xff0c;随着应用场景的复杂化&#xff0c;传统的卷积神经网络在处…

Webpack分包与合包深度解析

Webpack分包与合包深度解析 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家&#xff01;点我试试&#xff01;&#xff01; 引言&#xff1a;现代前端工程的模块化困境 在单页面应用&#xff08;SPA&#…

永恒之塔鼠标卡顿移动鼠标卡屏的问题

原因是现在鼠标普遍轮询率偏高导致系统性能开销过大 解决办法90块钱到淘宝雷蛇官网店买个最便宜的鼠标 然后安装Razer控制台,在性能栏把轮询率设置到最低(125)

Selenium遇到Exception自动截图

# 随手小记 场景&#xff1a;测试百度&#xff1a; 点击新闻&#xff0c;跳转到新的窗口&#xff0c;找到输入框&#xff0c;输入“hello,world" 等到输入框的内容是hello,world, 这里有个错误&#xff0c;少了一个] 后来就实现了错误截图的功能&#xff0c;可以参考 …

飞机大战lua迷你世界脚本

-- 迷你世界飞机大战 v1.2 -- 星空露珠工作室制作 -- 最后更新&#xff1a;2024年1月 ----------------------------- -- 迷你世界API适配配置 ----------------------------- local UI { BASE_ID 7477478487091949474-22856, -- UI界面ID ELEMENTS { BG 1, -- 背景 BTN_LE…

我的ChatGPT怎么登不上?

近期&#xff0c;不少用户反馈在使用ChatGPT时遇到登录困难、连接超时等问题。本文将从技术角度分析常见原因&#xff0c;并提供合规、安全的解决方案&#xff0c;同时结合开发者实际需求推荐实用工具&#xff0c;助您高效应对登录障碍。 ChatGPT登录失败的常见原因 网络环境限…

【MySQL】用MySQL二进制包构建docker镜像

一、实验背景 【MySQL&docker】基于CentOS7.5 编译制作MySQL5.7.28镜像 https://www.jianshu.com/p/71fd79b69a6b 用MySQL源码编译的docker镜像&#xff0c;体积过大&#xff0c;直奔3G了&#xff0c;你也不清楚&#xff0c;这点编译参数打出的体积怎么就这么大&#xff01…

快速熟悉JavaScript

目录 1.js的基本认知 2.js的基本语法 2.1 变量的声明 三个关键字的区别 2.2数据类型 2.2.1 基本数据类型 2.2.2 复杂数据类型 2.3对象的属性和方法 2.3.1属性 2.3.2访问方式 2.4.3动态操作 2.4.4方法 2.4字符串的常用属性和方法 2.5运算符 2.6逻辑控制语句 2.7函…

在 Windows 上最快速安装 Qt 5

引言 Qt 是一个强大的跨平台 C 开发框架&#xff0c;广泛应用于 GUI 开发、嵌入式系统和工业软件等领域。然而&#xff0c;许多开发者习惯于在 Linux&#xff08;如 Ubuntu&#xff09;环境下使用 Qt&#xff0c;而在 Windows 上搭建 Qt 开发环境时可能会遇到许多问题&#xf…

二、QT和驱动模块实现智能家居-----5、通过QT控制LED

在QT界面&#xff0c;我们要实现点击“LED”按钮就可以控制板子上的LED。LED接线图如下&#xff1a; 在Linux 系统里&#xff0c;我们可以使用2种方法去操作上面的LED&#xff1a; ① 使用GPIO SYSFS系统&#xff1a;这需要一定的硬件知识&#xff0c;需要设置引脚的方向、数值…

threejs:用着色器给模型添加光带扫描效果

第一步&#xff1a;给模型添加光带 首先创建一个立方体&#xff0c;不进行任何缩放平移操作&#xff0c;也不要set position。 基础代码如下&#xff1a; 在顶点着色器代码里varying vec3 vPosition;vPosition position;获得threejs自动计算的顶点坐标插值&#xff08;也就…

高频 SQL 50 题(基础版)_1141. 查询近30天活跃用户数

1141. 查询近30天活跃用户数 select activity_date day,count(distinct user_id) active_users from Activity where (activity_date<2019-07-27 and activity_date>DATE_sub(2019-07-27,INTERVAL 30 DAY)) group by(activity_date)

【Zinx】Day1:初识 Zinx 框架

目录 学习目标初识 Zinx 框架Zinx v0.2 代码实现准备工作创建 Zinx 框架创建 ziface 与 znet 模块 基础的 Server 实现在 ziface 下创建服务模块抽象层 iserver.go在 znet 下实现服务模块 server.go 封装 Connection在 ziface 创建 iconnection.go在 znet 创建 connection.go 回…

音频3A测试--AEC(回声消除)测试

一、测试前期准备 一台录制电脑:用于作为近段音源和收集远端处理后的数据; 一台测试设备B:用于测试AEC的设备; 一个高保真音响:用于播放设备B的讲话; 一台播放电脑:用于模拟设备A讲话,和模拟设备B讲话; 一台音频处理器(调音台):用于录制和播放数据; 测试使用转接线若…

项目准备(flask+pyhon+MachineLearning)- 2

目录 1. 注册页面的渲染 2.邮箱的注册验证 3.登录页面的渲染 1. 注册页面的渲染 使用render_template来渲染&#xff0c;注意这里的前端网页使用jinja2模板 详情大家可以参考jinja2介绍 注意每个网页上方都有导航条&#xff0c;大家可以使用jinja2的继承功能&#xff0c;写一…

unity调用本地部署deepseek全流程

unity调用本地部署deepseek全流程 deepseek本地部署 安装Ollama 搜索并打开Ollama官网[Ollama](https://ollama.com/download) 点击Download下载对应版本 下载后点击直接安装 安装deepseek大语言模型 官网选择Models 选择deepseek-r1&#xff0c;选择对应的模型&#xff0…

跨域问题解释及前后端解决方案(SpringBoot)

一、问题引出 有时,控制台出现如下问题。 二、为什么会有跨域 2.1浏览器同源策略 浏览器的同源策略 &#xff08; Same-origin policy &#xff09;是一种重要的安全机制&#xff0c;用于限制一个源&#xff08; origin &#xff09;的文档或 脚本如何与另一个源的资源进行…