详解Spring IoCDI(二)

news2024/11/18 22:32:59

目录

承接上文:详解Spring IoC&DI (一)

1.IoC详解

1.1方法注解@Bean

1.2方法注解要配合类注解使用 

1.3定义多个对象

1.4重命名Bean

1.5扫描路径

2.DI详解

2.1DI与IoC的关系

2.2属性注入

2.3构造方法注入

 2.4Setter注入

2.5 三种注入优缺点分析

2.6Autowired存在问题

2.6.1Primary

 2.6.2Qualifier

2.6.3Resource


承接上文:详解Spring IoC&DI (一)

1.IoC详解

1.1方法注解@Bean

类注解是添加到某个类上的  但是存在两个问:

1.使⽤外部包⾥的类, 没办法添加类注解

2.⼀个类, 需要多个对象, 比如多个数据源

这种场景, 我们就需要使⽤⽅法注解@Bean

代码示例:

 public class BeanConfig { 
     @Bean
     public User user(){
        User user = new User();
        user.setName("zhangsan");
        user.setAge(18);
         return user;
     }
 }

当我们写完以上代码 ,尝试获取 bean 对象中的 user 时却发现 ,根本获取不到:

@SpringBootApplication
public class TestSpringTwoApplication {

    public static void main(String[] args) {
  ApplicationContext context =  SpringApplication.run(TestSpringTwoApplication.class,args);
        //从Spring上下⽂中获取对象
        User user =context.getBean(User.class);
        //使⽤对象
        System.out.println(user);
    }
}

执行结果如下: 

1.2方法注解要配合类注解使用 

Spring 框架的设计中 ,⽅法注解 @Bean 要配合类注解才能将对象正常的存储到Spring 容器中

如下代码所示:

 @Component
 public class BeanConfig { 
     @Bean
     public User user(){
        User user = new User();
        user.setName("zhangsan");
        user.setAge(18);
         return user;
     }
 }

再次执⾏以上代码 ,运⾏结果如下:

1.3定义多个对象

多数据源的场景, 类是同⼀个, 但是配置不同, 指向不同的数据源.

@Component
public class BeanConfig {
    @Bean
    public User user1(){
        User user = new User();
        user.setName("zhangsan");
        user.setAge(18);
        return user;
    }
    @Bean
    public User user2(){
        User user = new User();
        user.setName("lisi");
        user.setAge(28);
        return user;
    }

}

获取对象:

@SpringBootApplication
public class TestSpringTwoApplication {

    public static void main(String[] args) {
        ApplicationContext context =  SpringApplication.run(TestSpringTwoApplication.class, args);
        //从Spring上下⽂中获取对象
        User user1 = (User) context.getBean("user1");
        User user2 = (User) context.getBean("user2");
        //使⽤对象
        System.out.println(user1);
        System.out.println(user2);
    }
}

运行结果:

1.4重命名Bean

可以通过设置 name 属性给 Bean 对象进⾏重命名操作 ,如下代码所示


 @Bean(name = {"u1","user1"})
 public User user1(){
     User user = new User();
     user.setName("zhangsan");
     user.setAge(18);
     return user;
 }

此时我们使用u1就可以获取到User对象:

 User u1 = (User) context.getBean("u1"); 

name={} 可以省略 ,如下代码所⽰: 

 @Bean({"u1","user1"})
 public User user1(){
     User user = new User();
     user.setName("zhangsan");
     user.setAge(18);
     return user;
 }

只有⼀个名称时, {}也可以省略, :

 @Bean("u1")
 public User user1(){
     User user = new User();
     user.setName("zhangsan");
     user.setAge(18);
     return user;
 }

1.5扫描路径

使⽤前⾯学习的四个注解声明的bean想要⽣效 ,还需要Spring扫描

通过修改项目工程的目录结构进行测试:

运行结果:

 解释: 没有bean的名称为u1,

使⽤五⼤注解声明的bean ,要想⽣效, 还需要配置扫描路径, Spring扫描到这些注解也就是通过

@ComponentScan来配置扫描路径.

@ComponentScan({"com.example.demo"}) 
@SpringBootApplication
public class TestSpringTwoApplication {

    public static void main(String[] args) {
  ApplicationContext context =  SpringApplication.run(TestSpringTwoApplication.class,args);
        //从Spring上下⽂中获取对象
        User user =context.getBean(User.class);
        //使⽤对象
        System.out.println(user);
    }
}

@ComponentScan注解虽然没有显式配置,但是实际已经包含在了启动类声明注解

@SpringBootApplication中了,默认扫描的范围是启动类所在包及其子包

 

2.DI详解

2.1DI与IoC的关系

DI(Dependency Injection,依赖注入)和 IoC(Inversion of Control,控制反转)有着密切的关系。 可以说 DI 是实现 IoC 的一种具体方式。 IoC 是一种设计思想,强调将对象之间的控制权进行反转,不再由对象自己去创建或获取其依赖,而是由外部(如框架)来控制和管理依赖关系的创建和注入。 而 DI 则侧重于具体的将依赖对象注入到目标对象的操作,它是实现 IoC 理念的重要手段之一。通过 DI,依赖对象在合适的时候被准确地注入到需要它们的对象中,从而体现了 IoC 的原则。 简单来说,IoC 是更宏观的概念,DI 是实现 IoC 的具体策略和机制。

关于依赖注⼊, Spring也给我们提供了三种⽅式:

属性注⼊(Field Injection)、构造⽅法注⼊(Constructor Injection)、Setter 注⼊(Setter Injection)

2.2属性注入

 @SpringBootApplication
 public class SpringIocDemoApplication { 

    public static void main(String[] args) { 
      //获取Spring上下⽂对象
       ApplicationContext context = SpringApplication.run(SpringIocDemoApplicatio 
      //从Spring上下⽂中获取对象
      UserController userController = (UserController) context.getBean("userCont 
      //使⽤对象
       userController.sayHi(); 11    }
 }

属性注⼊是使用@Autowired实现的 ,将 Service 类注⼊到 Controller 类中.

Service类的实现代码如下: 

 import org.springframework.stereotype.Service; 
 @Service
 public class UserService {
     public void sayHi() {
        System.out.println("Hi,UserService");
     }
 }

Controller 类的实现代码如下:

 @Controller
 public class UserController { 
     //注⼊⽅法1: 属性注⼊
     @Autowired
     private UserService userService;

     public void sayHi(){
         System.out.println("hi,UserController...");
        userService.sayHi();
        }
    }

获取Controller中的sayHi方法: 

 @SpringBootApplication
 public class SpringIocDemoApplication { 

    public static void main(String[] args) { 
      //获取Spring上下⽂对象
  ApplicationContext context =  SpringApplication.run(TestSpringTwoApplication.class,args);

      //从Spring上下⽂中获取对象
      UserController userController = context.getBean(UserController.class);
      //使⽤对象
       userController.sayHi(); 
    }
 }

 运行结果为:

2.3构造方法注入

构造方法注入是在类的构造方法中实现注入,如下代码所示:

@Controller
public class UserController2 { 
     //注⼊⽅法2: 构造⽅法
     private UserService userService; 

     @Autowired
     public UserController2(UserService userService) {
        this.userService = userService;
      } 

     public void sayHi(){
         System.out.println("hi,UserController2...");
        userService.sayHi();
     }
 }

注意事项:如果类只有⼀个构造⽅法 ,那么@Autowired 注解可以省略;如果类中有多个构造⽅法, 那么需要添加上@Autowired 来明确指定到底使⽤哪个构造⽅法。

 2.4Setter注入

Setter 注⼊和属性的 Setter 方法实现类似 ,只不过在设置 set 方法的时候需要加上@Autowired 解 ,如下代码所示:

 @Controller
 public class UserController3 { 
     //注⼊⽅法3: Setter⽅法注⼊
    private UserService userService; 

    @Autowired
     public void setUserService(UserService userService) {
        this.userService = userService;
      } 
     public void sayHi(){
         System.out.println("hi,UserController3...");
        userService.sayHi();
     }
    }

2.5 三种注入优缺点分析

属性注⼊

  优点: 简洁 ,使⽤⽅便; 

  缺点:只能⽤于 IoC 容器 并且只有在使⽤的时候才会出现 NPE 空指针异常)、 能注入⼀个Final修饰的属性

 构造函数注⼊(Spring 4.X推荐) 

 优点:可以注⼊final修饰的属性、注⼊的对象不会被修改、依赖对象在使⽤前⼀定会被完全初始化 ,因为依赖是在类的构造⽅法中执⾏的 ,⽽构造⽅法是在类加载阶段就会执⾏的⽅法、 通⽤性好, 构造⽅法是JDK⽀持的, 所以更换任何框架,他都是适⽤的

 缺点: 注入多个对象时, 代码会比较繁琐

  Setter注⼊(Spring 3.X推荐)

 优点: ⽅便在类实例之后, 重新对该对象进⾏配置或者注⼊

缺点:不能注⼊⼀个Final修饰的属性、注⼊对象可能会被改变, 因为setter⽅法可能会被多次调⽤ , 就有被修改的风险.

2.6Autowired存在问题

当同⼀类型存在多个bean, 使⽤@Autowired会存在问题


 @Component
 public class BeanConfig { 

     @Bean("u1")
     public User user1(){
        User user = new User();
        user.setName("zhangsan");
        user.setAge(18);
         return user;
     } 

     @Bean
     public User user2() {
        User user = new User();
        user.setName("lisi");
        user.setAge(19);
         return user;
     }
 }
 @Controller
 public class UserController { 

     //注⼊user 
     @Autowired
     private User user;

     public void sayHi(){
        System.out.println("hi,UserController...");
        userService.sayHi();
        System.out.println(user);
     }
 }

运行结果: 

报错的原因是 ,⾮唯—的 Bean 对象。

Spring提供了以下几种解决⽅案:

2.6.1Primary

@Primary注解: 当存在多个相同类型的Bean注⼊时 ,加上@Primary注解 来确定默认的实现.

 @Component
 public class BeanConfig { 

     @Primary //指定该bean为默认bean的实现
     @Bean("u1")
     public User user1(){
        User user = new User();
        user.setName("zhangsan");
        user.setAge(18);
         return user;
     } 
     @Bean
     public User user2() {
        User user = new User();
        user.setName("lisi");
        user.setAge(19);
         return user;
     }
 }

 2.6.2Qualifier

指定当前要注⼊的bean对象。 在@Qualifiervalue属性中 ,指定注⼊的bean 的名称。

 @Qualifier注解不能单独使⽤ ,必须配合@Autowired使用

 @Controller
 public class UserController {
     @Qualifier("user2") //指定bean名称
     @Autowired
     private User user;

     public void sayHi(){
         System.out.println("hi,UserController...");
        System.out.println(user);
     }
 }

2.6.3Resource

使⽤@Resource注解:是按照bean的名称进⾏注⼊。通过name属性指定要注⼊的bean的名称。

 @Controller
 public class UserController { 
     @Resource(name = "user2")
     private User user; 

     public void sayHi(){
         System.out.println("hi,UserController...");
        System.out.println(user);
           }
    }

@Autowird @Resource的区别

•  @Autowired spring框架提供的注解 ,而@ResourceJDK提供的注解

•  @Autowired 默认是按照类型注⼊ ,⽽@Resource是按照名称注⼊ . 相⽐于 @Autowired  来说, @Resource ⽀持更多的参数设置 ,例如 name 设置 ,根据名称获取 Bean

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

kettle 使用动态变量名定义变量

name是变量,value 值也是变量 我需要把name作为变量名,value作为变量值; 在kettle中,使用javascript脚本 key与lastVsxzl都是变量 //Script here setVariable(key,lastVsxzl,r);var rgetVariable(key,r); Demo 1、从记事本里面…

香橙派 AIpro上手体验并验证车道线识别算法

香橙派 AIpro上手体验并验证车道线识别算法 1.前言 最近入手了一块香橙派AIpro,体验了一下,感觉还不错,在这里分享给大家,大家可以做个参考。 2.开箱 整套产品包含一块主板、一个电源插头和一条双端Type-C的数据线,…

【会议征稿】2024年无人驾驶与智能传感技术国际学术会议(ADIST 2024)

2024年无人驾驶与智能传感技术国际学术会议(ADIST 2024)将于2024年6月28-30日在珠海召开。ADIST 2024旨在搭建学术资源共享平台,加强中外学术合作,促进自动驾驶和智能传感技术的发展,促进全球研究人员、开发人员、工程…

LTspice仿真中设置电阻随时间变化的方法

背景: 笔者找了很多资料都没有看到如何设置电阻、电容等参数随时间变化。但在实际模拟中,总会遇到需要模拟这些量的变化。故撰写此文,供大家参考。 除了模拟随时间变化外,同样的思路也可以模拟随其他变量变化 效果展示 设置电…

【网络研究观】-20240531

战争揭开美国武器优势的面纱 随着俄军在哈尔科夫地区稳步推进,乌克兰战争对美国国防机器而言是一场灾难,这一点越来越明显,这不仅是因为我们的援助未能挽救乌克兰的撤退和可能的失败。更重要的是,这场战争无情地暴露了我们国防体…

内网不能访问域名怎么办?

在网络应用中,我们常常遇到内网不能访问域名的问题。这是由于内网环境限制导致的,内网无法直接连接到公网,因而无法访问互联网上的域名。我们可以利用一些特殊技术和工具来解决这个问题。 天联组网技术的应用 天联组网是一种非常受欢迎的解决…

JS数组怎么去重?| JavaScript中数组去重的14种方法

目录 一、利用for循环嵌套去重 二、利用splice() for循环嵌套(ES5中最常用) 三、利用indexOf() for循环去重 四、利用sort() for循环去重 五、利用includes() for循环去重(ES7) 六、利用Object键值对及其hasOwnProperty…

在phpstorm2024版里如何使用Jetbrains ai assistant 插件 ?

ai assistant激活成功后,如图 ai assistant渠道:https://web.52shizhan.cn/activity/ai-assistant 在去年五月份的 Google I/O 2023 上,Google 为 Android Studio 推出了 Studio Bot 功能,使用了谷歌编码基础模型 Codey,Codey 是…

解锁 JavaScript ES6:函数与对象的高级扩展功能

个人主页:学习前端的小z 个人专栏:JavaScript 精粹 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结,欢迎大家在评论区交流讨论! ES5、ES6介绍 文章目录 ES6函数扩展1 默认参数1.1 之前写法1.2 ES6 写法1.3 注意点 2 …

python实现——综合类型数据挖掘任务(无监督的分类任务)

综合类型数据挖掘任务 航空公司客户价值分析。航空公司客户价值分析。航空公司客户价值分析。航空公司已积累了大量的会员档案信息和其乘坐航班记录(air_data.csv),以2014年3月31日为结束时间抽取两年内有乘机记录的所有客户的详细数据。利用…

python多种方式 保留小数点位数(附Demo)

目录 前言1. 字符串格式2. round函数3. Decimal模块4. numpy库5. Demo 前言 在Python中,保留小数点后特定位数可以通过多种方式实现 以下是几种常见的方法,并附上相应的代码示例: 使用字符串格式化(String Formatting&#xff…

Go 1.23新特性前瞻

2024年5月22日,Go 1.23版本[1]功能特性正式冻结,后续将只改bug,不增加新feature。 对Go团队来说,这意味着开始了Go 1.23rc1的冲刺,对我们普通Gopher而言,这意味着是时候对Go 1.23新增的功能做一些前瞻了&am…

ad18学习笔记20:焊盘设置Solder Mask Expansion(阻焊层延伸)

【AD18新手入门】从零开始制造自己的PCB_ad18教程-CSDN博客 Altium Designer绘制焊盘孔(Pad孔)封装库的技巧,包括原理图封装和PCB封装_哔哩哔哩_bilibili 默认的焊盘中间是有个过孔的,单层焊盘(表贴烛盘)…

ARM学习(28)NXP 双coreMCU IMX1160学习

笔者最近接触到一块IMXRT1160的双core板子,特依次来记录学习一下 1、IMXRT1160 板子介绍 介绍一下NXP的Demo板子,是一个双core的板子,Cortexm7和Cortexm4,总计1MB的RAM空间,256KB的ROM空间,提供了丰富的内…

【GD32】05 - PWM 脉冲宽度调制

PWM PWM (Pulse Width Modulation) 是一种模拟信号电平的方法,它通过使用数字信号(通常是方波)来近似地表示模拟信号。在PWM中,信号的占空比(即高电平时间占整个周期的比例)被用来控制平均输出电压或电流。…

IDEA一键启动多个微服务

我们在做微服务项目开发的时候,每次刚打开IDEA,就需要把各个服务一个个依次启动,特别是服务比较多时,逐个点击不仅麻烦还费时。下面来说一下如何一键启动多个微服务。 操作步骤 点击Edit Configurations 2.点击“”,…

BSD盲区检测系统性能要求及试验方法

相关术语 盲区检测(bsd,blind spot detection)试验车辆(subject vehicle)目标车辆(target vehicle)横向距离(lateral distance):试验车车身最外缘(不包含外后视镜)与目标车辆车身最外缘(不包含外后视镜)之间的横向距离。 纵向距离(longitudinal distance):试验…

用windows server backup备份文件夹到网络共享文件夹并恢复

一、备份 开始 运行windows server backup,在右边的窗格中点击“备份计划” 选择备份配置 因为我们要备份的是一个文件夹,所以,选“自定义”,卷即为磁盘分区。 选择要备份的项 点击添加项目,可依次添加多个备份项目。 勾选需要…

职场思考-阅读专业与技能同步增长(12)

我们可以发现一个人“逆袭”的关键就是先要改变自己的思想,而机遇、资源都是外部条件。 改变思想无非也就几个途径: 一是阅读换脑,二是遇贵人点拨,三是社会“碰壁”后的反思并改正 对于职场进阶而言,阅读更是必要手段 …

知名专业定制线缆知名智造品牌推荐-精工电联:解决水下机器人线缆行业痛点的领航者

在科技日新月异的今天,精工电联作为高科技智能化产品及自动化设备专用连接线束和连接器配套服务商,致力于为高科技行业提供高品质、高性能的集成线缆和连接器定制服务。我们不仅是高品质定制线缆供应商,更是水下机器人线缆行业痛点的有效解决…