当前位置: 首页 > news >正文

Spring两个核心IoCDI(二)

DI(依赖注入)就是从IoC容器中获取对象并赋值给某个属性,这就是依赖注入的过程。

关于依赖注入有3种方式:

1、属性注入

2、构造方法注入

3、setter注入

目录

1、属性注入

2、 构造方法注入

3、Setter方法注入

4、3种注入方式优缺点分析

属性注入

构造方法注入:

Setter注入

5、@Autowired存在的问题以及解决方法

面试题

3种注入方式优缺点

@Autowired与@Resource的区别:

@Autowired的装配顺序


1、属性注入

@Service
public class UserService {public void doService(){System.out.println("UserService.doService");}
}
@ResponseBody
@Controller
public class UserController {@Autowiredprivate UserService userService;public void sayHi() {userService.doService();System.out.println("UserController.sayHi");}@RequestMapping("/hello")public String hello(){return "hello";}
}
@SpringBootApplication
public class SpringIoCDemoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(SpringIoCDemoApplication.class, args);UserController bean = context.getBean(UserController.class);bean.sayHi();
}
}

通过@Autowired注解,spring就会从容器中取出UserService对象赋值给userService属性,如果不加这个注解,就会在userService.doService()这里报空指针异常。

ApplicationContext的对象也在spring IoC容器中,我们也能通过 @Autowired拿到它的对象,

 @Autowired
    private ApplicationContext context;然后用context再去获取别的Bean对象。

但是我们一般不这样用。

2、 构造方法注入

@Service
public class UserService {public void doService(){System.out.println("UserService.doService");}
}
@Controller
public class UserController2 {private UserService userService;public UserController2(UserService userService){this.userService = userService;}public void sayHi() {userService.doService();System.out.println("UserController.sayHi");}
}
@SpringBootApplication
public class SpringIoCDemoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(SpringIoCDemoApplication.class, args);UserController2  uc = context.getBean(UserController2.class);uc.sayHi();
}
}

spring在创建UserController2对象的时候,因为这里只提供了一个需要UserService对象参数的构造方法,所以容器就会把UserService对象注入给this.userSercice属性,因此uc.sayHi()能成功运行。

但是为了标准化一般建议把无参的构造方法也写上,

@Controller
public class UserController2 {private UserService userService;public UserController2() {}public UserController2(UserService userService){this.userService = userService;}public void sayHi() {userService.doService();System.out.println("UserController.sayHi");}
}

此时再运行起来就会报错,

因为spring在创建UserController2对象的时候有无参的构造方法就是用了无参的构造方法,所以就没有给userService属性赋值,因此userService.doService()这行会报空指针异常。

为了让spring创建UserController2对象使用有UserService参数的构造方法,我们需要使用@Autowired注解

import com.bit.springiocdemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;@Controller
public class UserController2 {private UserService userService;public UserController2() {}@Autowiredpublic UserController2(UserService userService){this.userService = userService;}public void sayHi() {userService.doService();System.out.println("UserController.sayHi");}
}

所以只有一个构造方法时,@Autowired可以省略;有多个构造方法时需要通过添加@Autowired来指定spring用哪一个来创建对象。

3、Setter方法注入

import com.bit.springiocdemo.config.UserConfig;
import com.bit.springiocdemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;@Controller
public class UserController3 {private UserService userService;private UserConfig userConfig;@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}@Autowiredpublic void setUserConfig(UserConfig userConfig) {this.userConfig = userConfig;}public void sayHi() {userService.doService();userConfig.doConfig();System.out.println("UserController.sayHi");}
}
@SpringBootApplication
public class SpringIoCDemoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(SpringIoCDemoApplication.class, args);UserController3 uc3 = context.getBean(UserController3.class);uc3.sayHi();
}
}

通过setter方法来为属性赋值,需要给setter方法添加@Autowired属性,否则在sayHi()方法中就会报快指针异常。

4、3种注入方式优缺点分析

属性注入

简洁方便,但是只能用于IoC容器,并且不能注入一个Final修饰的属性。

fianl修饰的属性要么要初始化,要么通过构造方法进行赋值。

构造方法注入:

优点:

  • 可以注入final修饰的属性,就是在构造方法中进行赋值
  • 注入的对象不会被修改
  • 依赖对象在使用前一定会被完全初始化的,因为依赖是在类的构造方法中注入的,而构造方法是在类加载时就会执行的
  • 通用性好,构造方法是jdk支持的,换任何框架都是适用的

缺点:注入多个对象比较麻烦

Setter注入

优点:方便在类实例话之后,还能对该对象进行配置或者注入

@Controller
public class UserController3 {private UserService userService;private UserConfig userConfig;@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}@Autowiredpublic void setUserConfig(UserConfig userConfig) {this.userConfig = userConfig;}public void sayHi() {userService.doService();userConfig.doConfig();System.out.println("UserController.sayHi");}
}

就这个代码来说,就是在UserController3实例化好之后,还能通过主动调用setter方法来给属性赋值,更换注入的对象,所以这也是一个缺点

缺点:

  • 注入对象可能会被改变,因为setter可能多次调用,就有被修改的风险
  • 不能注入一个final修饰的属性

当前Spring官方更推荐构造方法注入方式,程序员更推荐属性注入方式。

5、@Autowired存在的问题以及解决方法

当一个类型有多个Bean时,使用@Autowired就会报错

@AllArgsConstructor
@Data
public class UserInfo {private Integer id;private String name;private Integer age;
}
@Configuration
public class UserInfoConfig {@Bean(name = {"user1","lisi"})public UserInfo user1() {UserInfo userInfo = new UserInfo(1,"lisi",15);return userInfo;}@Beanpublic UserInfo user2() {UserInfo userInfo = new UserInfo(2,"kiku",31);return userInfo;}
}

从这里可以看到UserInfo类型在IoC容器中存了两个对象,一个是通过user1()创建的,一个是user2()创建的

@Controller
public class UserController {@Autowiredprivate  UserService userService;@Autowiredprivate UserInfo userInfo;public void sayHi() {userService.doService();System.out.println(userInfo);System.out.println("UserController.sayHi");}
}

所以这里通过添加@Autowired给userInfo属性注入对象时,不知道该使用容器中的哪一个来进行注入

@SpringBootApplication
public class SpringIoCDemoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(SpringIoCDemoApplication.class, args);UserController bean = context.getBean(UserController.class);bean.sayHi();
}
}

报错信息以及建议:

建议中有两种解决方式,

一种是通过添加@Primary来选择一个Bean对象作为主要选择的、默认的,比如:

@Primary
@Bean(name = {"user1","lisi"})
public UserInfo user1() {UserInfo userInfo = new UserInfo(1,"lisi",15);return userInfo;
}

这样就会选择user1()创建的对象来注入。

另一种是通过@Qualifier来指定要注入的对象是谁。

@Controller
public class UserController {@Autowiredprivate  UserService userService;@Autowired@Qualifier("user2")private UserInfo userInfo;public void sayHi() {userService.doService();System.out.println(userInfo);System.out.println("UserController.sayHi");}
}

当两个同时@Primary和@Qualifier都存在时,会使用@Qualifier()指定的,而不是默认的。

另外@Qualifier除了可以加在属性上,还可以加在参数上:

  @Autowiredpublic UserController2(UserService userService, UserConfig userConfig,@Qualifier("user1") UserInfo userInfo) {this.userService = userService;this.userConfig = userConfig;this.userInfo = userInfo;}

除了spring建议的这两种,我们还可以通过@Resource来解决:

//    @Autowired
//    @Qualifier("user2")@Resource(name = "user2")private UserInfo userInfo;

@Resource作用上就等于@Autowired+@Qualifier,

这个注解是jakarta提供的。

面试题

3种注入方式优缺点

@Autowired与@Resource的区别:

1、来源不同,@Autowired是spring框架提供的注解,@Resource是jdk提供的注解。

2、@Autowired是按照类型注入的(如果该类型只有一个Bean,直接注入;如果该类型有多个bean,就按属性名称注入,但是@Autowired不能指定bean的名称来注入),

@Resource是按照名称注入的

@Autowired的装配顺序

http://www.dtcms.com/a/342810.html

相关文章:

  • 【信创系统】信创系统传输文件
  • 科普:Python 中颜色的格式: RGB 格式 v.s. RGBA 格式
  • Terraform vs Ansible:基础设施即代码(IaC)工具深度对比与实战指南
  • 哈尔滨服务器托管,如何实现高效稳定运行?
  • 泛型与反射
  • MySQL--MVCC
  • MPS MPQ2013AGQ-AEC1-Z MPS芯源汽车级 同步降压转换器IC 电源传感器IC
  • 【密码学】深入浅出栅栏密码:原理、流程与实现
  • Android:compose-Scaffold组件
  • 【CS创世SD NAND征文】存储芯片在工业电表中的应用与技术演进
  • 基于Python与Tkinter开发的微博多功能自动化助手
  • 构建包含IK插件(中文分词插件)的Elasticsearch镜像
  • 分治思想在系统分流削峰中的实践与Golang前沿实现
  • RK3568项目(十六)--linux驱动开发之块设备介绍
  • C++ 序列式容器深度解析:vector、string、deque 与 list
  • 虚幻基础:曲线
  • Go 并发编程-channel
  • Java的反射与枚举
  • 贪吃蛇游戏(纯HTML)
  • 服务发现与负载均衡:Kubernetes Service核心机制深度解析
  • Vue数据的变更操作与表单数据的收集【6】
  • 动漫短剧小程序系统开发|动漫短剧小程序搭建|动漫短剧源码交付
  • 后浪来袭:NIST 轻量级密码标准化决赛圈算法剖析(ASCON、SPARKLE 等)
  • AI翻唱实战:用[灵龙AI API]玩转AI翻唱 – 第6篇
  • RocketMQ 消息消费 单个消费和批量消费配置实现对比(Springboot),完整实现示例对比
  • TCP连接
  • 华为开发者空间训练营-优秀作品公布
  • PyTorch深度学习遥感影像地物分类与目标检测、分割及遥感影像问题深度学习优化——CNN原理、Faster RCNN/YOLO检测到U-Net分割等
  • 13、按键输入检测
  • ES_索引模板