千家信息网

如何理解IoC的依赖注入

发表于:2024-10-22 作者:千家信息网编辑
千家信息网最后更新 2024年10月22日,这篇文章主要讲解了"如何理解IoC的依赖注入",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"如何理解IoC的依赖注入"吧!一、注解驱动IoCxml驱动的
千家信息网最后更新 2024年10月22日如何理解IoC的依赖注入

这篇文章主要讲解了"如何理解IoC的依赖注入",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"如何理解IoC的依赖注入"吧!

一、注解驱动IoC

xml驱动的IoC容器使用的是ClassPathXmlApplicationContext读取xml内bean信息

注解驱动的IoC容器使用的是AnnotationConfigApplicationContext读取Java类中的bean信息

1. AnnotationConfigApplicationContext 的注册使用

相比于xml文件作为驱动, 注解驱动需要指明配置类 一个配置类可以理解为"相当于"一个xml 配置类只需要在类上标注注解 @Configuration

@Configuration public class DemoConfiguration { }

在xml中声明bean的方式

在配置类中使用的是@Bean注解

说明: 向IoC容器注册一个类型为Persion,id为Person的Bean

方法名表示的是bean的id 返回值表示的是注册的bean的类型

@Bean注解也可以显示的声明bean的id 如 @Bean("person1")

@Bean public Person person() {     return new Person(); }

2. 注解IoC容器的初始化

public class AnnotationConfigApplication {     public static void main(String[] args) {         ApplicationContext ctx = new AnnotationConfigApplicationContext(DemoConfiguration.class);         Person person = ctx.getBean(Person.class);         System.out.println(person);     } }

运行后Person控制台打印结果

com.huodd.bean.Person@55536d9e

3. 组件的注册和扫描

上述初始化时 我们在使用AnnotationConfigApplicationContext时传递了参数 Class... componentClasses

翻看AnnotationConfigApplicationContext的构造方法可以发现还可以传递参数的参数类型还有 String... basePackages

这里就涉及到组件的注册和扫描

  • 这里可以思考一个问题, 如果我们要注册的组件特别多, 那进行编写这些@Bean的时候代码工作量也会特别多,这时候该如何解决呢?

Spring 给我们提供了几个注解,可以帮助我们快速注册需要的组件, 这些注解被称为模式注解(stereotype annotations)

@Component

@Component可以说是所有组件注册的根源 在类上标注 @Component 代表该类被注册到IoC容器中作为一个Bean

@Component public class Person { }

如果未指定 Bean 的名称 默认规则是 "类名称首字母小写" 上面的bean名称默认会是 person

如果要自定义bean的名称 可以在@Component声明value的值即可 如

@Component("person1") public class Person { }

在xml中相当于

@ComponentScan

这个时候 如果我们直接运行启动类 获取Person的bean对象,会报错NoSuchBeanDefinitionException 这是为什么呢?

因为我们只是声明了组件,而后直接启动了IoC容器,这样容器是感知不到有@Component存在的,

解决方案1:

我们需要在写配置类时再额外标注一个新的注解@ComponentScan

目的是告诉IoC容器 我要扫描哪个包下面的带有@Component注解的类

@Configuration @ComponentScan("com.huodd.bean") public class DemoComponentScanConfiguration { }

: 如果不指定扫描路径, 则默认扫描本类所在包及所有子包下带有@Component的组件

启动类代码如下:

public class AnnotationConfigApplication {     public static void main(String[] args) {         ApplicationContext ctx = new AnnotationConfigApplicationContext(DemoComponentScanConfiguration.class);         Person person = ctx.getBean(Person.class);         System.out.println(person);     } }

解决方案2:

这里也可以不写@ComponentScan 而直接在AnnotationConfigApplicationContext方法参数内传入String类型的包扫描路径 代码如下

public class AnnotationConfigApplication {     public static void main(String[] args) {         ApplicationContext ctx = new AnnotationConfigApplicationContext("com.huodd.bean");         Person person = ctx.getBean(Person.class);         System.out.println(person);     } }

PS: 组件扫描并非是注解驱动IoC所特有的, 其实在xml驱动的IoC模式下 同样可以启用组件扫描, 只需要在xml中声明一个标签即可

这里需要注意下: 如需要扫描多个路径,需要写多个标签 也就是 一个标签只能声明一个根包

组件注册的补充

SpringFramework 提供了在进行Web开发三层架构时的扩展注解: 分别为 @Controller、 @Service 、@Repository 小伙伴有没有很熟悉?

分别代表 表现层、业务层、持久层 这三个注解的作用与 @Component完全一样 扒开源码我们可以看到 底层在这三个注解类上又添加了 @Component

@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Service { }

这样 我们在进行符合三层架构的开发时 对于相应的如 ServiceImpl等 就可以直接标注 @Service 等注解了

@Configuration

@Configuration 底层也有标注@Component

@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Configuration { ... }

由此可以说明,配置类不是向我们所想的那样,只是单纯的做一个配置而已, 它也会被视为 bean,也被注册到IoC容器里面

4. 注解驱动与xml驱动互相引用

4.1 xml引用注解

需开启注解配置 再注册相应配置类

                       

4.2 注解引用XMl

@Configuration @ImportResource("classpath:annotation/demo-beans.xml") public class ImportXmlAnnotationConfiguration {  }

二、IoC的依赖注入

1.Setter属性注入

创建对象 将属性值set进去 之后返回对象

@Bean public Person person() {     Person person = new Person();     person.setId(1);     person.setName("PoXing");     person.setAge(18);     return person; }

xml中的setter注入

                

2. 构造器注入

使用构造器注入,需要在bean本身添加有参构造方法, 如在Person中添加有参构造方法如下

public Person(Integer id, String name, Integer age) {         this.id = id;         this.name = name;         this.age = age; }

注解驱动中,我们创建bean的时候注入属性时 就需要同时指定参数值

@Bean public Person person() {     return new Person(1, "PoXing", 18); }

xml驱动中如下

                     

3. 注解式属性注入

这里先说明一下,为何会有注解式属性值注入. 细心的小伙伴可能会发现 上面我们谈到的 Setter属性注入、构造器注入 好像在只能是在使用 @Bean注解的时候时候使用, 但是 如果是通过标注 @Component注解的组件呢(像前面我们的Person类中标注了@Component注解),怎么给它设定属性值, 该节主要就是说一下这部分

@Component 下的属性注入

这里我们使用Dog类做为演示(这里我悄悄的添加了@Component注解 自己尝试的小伙伴要注意哦 否则会报错的)

@Component public class Dog {     private Integer id;     private String name;     private Integer age;     ... 省略 Getter、Setter    ... 省略 toString  }

这里要实现注解式属性注入,可以直接在要注入的字段上标注 @Value注解 如

@Value("1") private Integer id;  @Value("wangcai") private String name;  @Value("3") private Integer age;

启动类代码如下

public class DiApplication {     public static void main(String[] args) {         ApplicationContext ctx = new AnnotationConfigApplicationContext("com.huodd.bean");         Dog dog = ctx.getBean(Dog.class);         System.out.println(dog);     } }

控制台打印结果

Dog{id=1, name='wangcai', age=3}

外部配置文件(@PropertySource)

这里主要是解决上面的@Value中注入 我们把属性值直接固定写死了,如果要修改 还要去Java代码中去修改,很不符合开发规范,

SpringFramework为我们扩展了新的注解@PropertySource 主要用来导入外部配置文件

1.这里我们创建一个 dog.properties

dog.id=1 dog.name=wangcai dog.age=3

2.引入配置文件

@PropertySource("classpath:di/dog.properties") @ComponentScan("com.huodd.bean") @Configuration public class DemoComponentScanConfiguration { }

3.Dog类中属性注入 这里@Value需要配合占位符 来获取properties配置文件中的内容

@Value("${dog.id}") private Integer id;  @Value("${dog.name}") private String name;  @Value("${dog.age}") private Integer age;

4.修改一下启动类

public class DiApplication {     public static void main(String[] args) {         ApplicationContext ctx = new AnnotationConfigApplicationContext(DemoComponentScanConfiguration.class);         Dog dog = ctx.getBean(Dog.class);         System.out.println(dog);     } }

控制台打印结果如下

Dog{id=1, name='wangcai', age=3}

此时配置文件的属性已经注入成功

4.自动注入

在xml模式中有ref属性 可以将一个bean注入到另外一个bean中, 注解模式中也同样可以

@Autowired

给Dog的bean中注入 Person的Bean (即 给dog指定它的主人)

方法1 → 在属性上标注

@Component public class Dog {     // ......     @Autowired     private Person person; }

方法2 → 使用构造器注入方式

@Component public class Dog {     // ......     private Person person;      @Autowired     public Dog(Person person) {      this.person = person;     } }

方法3 → 使用setter方法注入

@Component public class Dog {     // ......     private Person person;          @Autowired     public void setPerson(Person person) {         this.person = person;     } }

JSR250规范下的@Resource

@Resource也是用来属性注入的注解

它与@Autowired的区别是:

  • @Autowired是按照类型注入

  • @Resource是按照属性名(也就是bean的名称)注入

@Resource 注解相当于标注 @Autowired @Qualifier

@Qualifier这里简要说明下,为指定bean的名称而存在,如果存在多个相同的bean,而bean的名称不同,我们可以使用@Autowired 配置 @Qualifier注解

如: 下面表示该Dog类注入的主人Bean是名称为 xiaowang的, 而当前容器内可能存在多个 主人bean对象 比如 xiaoli、xiaoming ....

@Component public class Dog {     // ......     @Autowired     @Qualifier("xiaowang")     private Person person; }

下面如果使用@Resource 可以更方便些 代码如下

@Component public class Dog {     // ......     @Resource(name="xiaowang")     private Person person; }

JSR330规范下的@Inject

@Inject注解也是按照类型注入,与@Autowire的策略一样, 不过如要使用@Inject 需要额外的导入依赖

      javax.inject     javax.inject     1 

后面的使用方法就与SpringFramework 原生的 @Autowire + @Qualifier 相同了

@Component public class Dog {          @Inject // 等同于@Autowired     @Named("xiaowang") // 等同于@Qualifier     private Person person;

它与@Autowired的区别是:

  • @Autowired所在的包为 org.springframework.beans.factory.annotation.Autowired 即为 SpringFramework 提供的

  • @Inject所在的包为 javax.inject.Inject 属于JSR的规范 也就是说如果不使用SpringFramework时可以使用该注解

5. 复杂类型注入

Array注入

              PoXing         LaoWang      

List注入

              13000000000         13000000001      

Set注入-

  ---                               

Map注入

                                                                       

Properties注入

                       18      

面试题

1.@Autowired注入原理是什么?

  1. 鸿蒙官方战略合作共建--HarmonyOS技术社区

  2. 先拿属性对应的类型,去IoC容器中找相应的Bean

  3. 如果没有找到 直接抛出NoUniqueBeanDefinitionException异常

  4. 如果找到一个 直接返回

  5. 如果找到多个相同类型的bean 再拿属性名去与这多个bean的id进行对比

  6. 如果有多个或者没有 则会抛出NoUniqueBeanDefinitionException异常

  7. 如果只有一个 直接返回

2.依赖注入的方式有哪些,都有什么区别

3.自动注入的注解对比

@Qualifier :如果被标注的成员/方法在根据类型注入时发现有多个相同类型的 Bean ,则会根据该注解声明的 name 寻找特定的 bean

@Primary :如果有多个相同类型的 Bean 同时注册到 IOC 容器中,使用 "根据类型注入" 的注解时会注入标注 @Primary 注解的 bean 即默认策略

4.使用依赖注入有什么优缺点

依赖注入作为 IOC 的实现方式之一,目的就是解耦,我们不需要直接去 new 那些依赖的类对象就可以直接从容器中去取来使用, 如果组件存在多级依赖,依赖注入可以将这些依赖的关系简化。

依赖对象的可配置:通过 xml 或者注解声明,可以指定和调整组件注入的对象,借助 Java 的多态特性,可以不需要大批量的修改就完成依赖注入的对象替换

感谢各位的阅读,以上就是"如何理解IoC的依赖注入"的内容了,经过本文的学习后,相信大家对如何理解IoC的依赖注入这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

注解 属性 配置 容器 类型 组件 方法 驱动 多个 对象 名称 代码 文件 相同 参数 时候 上标 方式 模式 构造器 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 游戏服务器会关掉吗 浪潮机架式服务器总代理 南京 软件开发有限公司 时间戳服务器招标 表格v不过来数据库 金山区常规软件开发销售价格 考研网络安全方向 邵东租房网络安全 网络安全专业硕士好就业吗 江苏网络技术咨询五星服务 网络安全治理存在的问题 德惠通用网络技术咨询服务保障 网络安全宣传进入社区 服务器如何负载均衡 服务器的辐射安全距离 校园网络安全实用案例 安徽软件开发者收费标准 虹口区智能化软件开发采购 方舟服务器地区买错了影响吗 服务器怎么控制局域网电脑 游戏服务器会关掉吗 存储服务器 价格 深圳市众想网络技术有限公司 福州设备信息化管理软件开发 陕西浪潮服务器虚拟化价格 网络安全产品经理工资一般多少 江苏网络技术咨询五星服务 德惠通用网络技术咨询服务保障 济南85软件开发公司 包头跑腿app软件开发多少钱
0