Spring IoC&DI(下)

前言:书接上回,该篇博客主要讲解DI与该章节常见面试题

1. DI详解(IoC的实现)

DI即依赖注入,是指IoC容器在创建Bean时,去提供运行时所依赖的资源,而资源指的就是对象。说白了就是把对象取出来放到某个类的属性中。
关于依赖注入,Spring也给我们提供了三种方式:

  1. 属性注入(Field Injection)
  2. 构造方法注入(Constructor Injection)
  3. Setter注入(Setter Injection)
    接下来我将演示使用这三种方式把Sevice类注入到Controller类中。

1.1 属性注入

属性注⼊是使⽤@Autowired实现的,将Service类注入到Controller类中.
Service类的实现代码如下:

package com.example.demo.service;

import org.springframework.stereotype.Service;

@Service
public class UserService {
    public void sayHi() {
        System.out.println("hi service!!!");
    }
}

而Controller类的实现代码如下:

package com.example.demo.controller;

import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller //将对象存储至Spring中
public class UserController {
    //注入方法1:属性注入
    @Autowired
    private UserService userService;
    public void sayHi(){
        System.out.println("你好,UserController");
        userService.sayHi();
    }
}

获取Controller类中的sayHi方法:

@SpringBootApplication
public class IocDemoApplication {

    public static void main(String[] args) {
        //获取Spring上下文对象
        ApplicationContext context = SpringApplication.run(IocDemoApplication.class, args);
        //从Spring上下文中获取对象
        UserController userController = context.getBean(UserController.class);
        //使用对象
        userController.sayHi();
    }
}

运行结果如下:

然后我们将@AutoWired注释掉,再看看运行结果:(提示"this.userService" is null)

👊注意:@AutoWired注入时是根据类型注入(进行匹配)的,所以上方:private UserService userService;的userService可随意命名,无需固定格式。

1.2 构造方法注入

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

@Controller
public class UserController2 {
    //注⼊⽅法2: 构造⽅法
    private UserService userService;
    @Autowired
    public UserController2(UserService userService) {
        this.userService = userService;
    }
    public void sayHi(){
        System.out.println("你好,UserController2");
        userService.sayHi();
    }
}

⭐⭐注意:

  1. 如果类只有⼀个构造方法,那么@Autowired注解可以省略;但假如这个构造方法是无参的话,项目运行会报空指针异常。
  2. 如果类中有多个构造方法,Spring会默认调用无参构造方法,没有的话同样会报错,这是就需要添加**@Autowired**来明确指定到底使用哪个构造方法。

1.3 Setter注入

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("你好,UserController3");
                userService.sayHi();
            }
        }

如若不加@AutoWired注解,会报空指针异常。

2 三种注入方式的优与劣

1. 属性注入

  • 优:简洁,使用方便
  • 劣:
  1. 只能用于IoC容器,如果是非IoC容器不可用,并且只有在使用的时候才会出现NullPointerException(空指针异常)
  2. 不能注入一个Final修饰的属性,解决方案如下:
  • 定义时就进行赋值
  • 构造方法中进行赋值
  1. 如果一个类型存在多个对象时,优先名称匹配,如果名称匹配不上,则会报错

2. 构造函数注入(Spring4.X推荐)

  • 优:
  1. 可以注入final修饰的属性
  2. 注入的对象不会被修改
  3. 依赖对象在使用前⼀定会被完全初始化,因为依赖是在类的构造方法中执行的,而构造方法
    是在类加载阶段就会执行的方法。
  4. 通⽤性好,构造方法是JDK支持的,所以更换任何框架,他都是适用的。
  • 劣: 注入多个对象时,代码会比较繁琐

3. Setter注入(Spring 3.X推荐)

  • 优:方便在类实例之后,重新对该对象进行配置或者注入(用处不大🤭🤭)
  • 劣:
  1. 不能注入一个Final修饰的属性。
  2. 注入对象可能会改变,因为setter方法可能会被多次调用,其中便会产生被修改的风险。

3 @AutoWired存在的问题

当同一类型存在多个bean时,使用@AutoWired便会存在问题


此时idea直接给出了一个error,运行是一定出问题的,如下图:

大致意思就是:不是唯一的bean对象

4 解决方案

  • 属性名与需要使用的对象保持一致(不推荐)
  • @Primary
  • @Qualifier
  • @Resource

4.1 @Primary

使用@Primary注解:当存在多个相同类型的Bean注入时,加上该注解来确定默认的实现
示例代码如下:

4.2 @Qualifier

使用@Qualifier注解:指定当前要注入的bean对象。在@Qualifier的value属性中,指定注入的bean的名称
📌注意:@Qualifier注解不能单独使用,必须配合@Autowired使用
示例如下:

4.3 @Resource(常用)

使用@Resource注解:是按照bean的名称进行注入。通过name属性指定要注入的bean的名称。
示例代码如下:

当然,如果你使用了@Resource注解,并且通过它来进行依赖注入,就不需要再使用@Autowired注解了。

5 常见面试题

5.1 @Autowired和@Resource区别?

  • @Autowired是spring框架提供的注解,而@Resource是JDK提供的注解
  • @Autowired默认是按照类型注入,而@Resource则是按照名称注入。相比于@Autowired来说,@Resource支持更多的参数设置,比如name设置,根据名称获取Bean。

5.2 Spring,SpringMVC,SpringBoot的关系以及区别?

  • 区别:
  1. Spring:是一个综合性的 Java 开发框架,提供了诸多功能,包括依赖注入、面向切面编程、事务管理等。
  2. Spring MVC:是 Spring 框架中的一个模块,用于构建基于 MVC 架构的 Web 应用程序。
  3. Spring Boot:是 Spring 项目的一个子项目,旨在简化 Spring 应用程序的开发和部署,提供了自动配置和快速启动的能力。
  • 关系:
  1. Spring MVC 是 Spring 框架的一部分,用于构建 Web 应用程序。
  2. Spring Boot 基于 Spring 框架,为 Spring 应用程序提供了自动配置和快速启动的能力。

总的来说,Spring 是一个全功能的 Java 开发框架,Spring MVC 是 Spring 框架的 Web 模块(Spring Web),而 Spring Boot 是一个简化 Spring 应用程序开发的工具。

5.3 ApplicationContext与BeanFactory的区别?

选中ApplicationContext,按下CTRL+ALT+U,即可生成当前接口的继承关系图,如下图:
在这里插入图片描述
区别总结如下:

  • 初始化时机:
    BeanFactory:延迟初始化,即在第一次请求时才会实例化bean。
    ApplicationContext:预先实例化所有的单例bean,在容器启动时就完成了bean的初始化。
  • Bean实例化方式:
    BeanFactory:使用 getBean() 方法获取bean实例。
    ApplicationContext:除了可以使用 getBean() 方法外,还支持自动注入、Bean的生命周期回调等功能。
  • 继承关系与功能:
    BeanFactory和ApplicationContext都是 Spring 框架中的顶级接口。它们是 Spring 容器的两个主要实现,负责管理和装配 bean,并提供了对 Spring 应用程序上下文的访问和控制。其中BeanFactory提供了基础的访问容器的能力,而ApplicationContext属于BeanFactory的子类,它除了继承了BeanFactory的所有功能之外,它还拥有独特的特性,还添加了对国际化支持、资源访问支持、AOP支持、以及事件传播等方面的支持。
  • 性能:
    BeanFactory:由于延迟初始化的特性,相对于 ApplicationContext,启动速度会更快一些。
    ApplicationContext:在初始化时会预先加载和实例化所有的单例bean,因此在启动时会消耗更多的资源和时间。
    所以,一般如果应用需要更多的功能,像事件处理、AOP、国际化等,建议使用 ApplicationContext;而如果应用对性能要求较高,可以考虑使用 BeanFactory。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值