【JavaEE】-- IoC & DI

文章目录

  • [1. Spring、Spring Boot 和 Spring MVC 的关系和区别?(常见面试题)](#1. Spring、Spring Boot 和 Spring MVC 的关系和区别?(常见面试题))
    • [1.1 Sring](#1.1 Sring)
    • [1.2 Spring MVC](#1.2 Spring MVC)
    • [1.3 Spring Boot](#1.3 Spring Boot)
    • [1.4 总结](#1.4 总结)
  • [2. IoC](#2. IoC)
    • [2.1 Bean的存储](#2.1 Bean的存储)
    • [2.2 Bean的命名](#2.2 Bean的命名)
    • [2.3 方法注解@Bean](#2.3 方法注解@Bean)
      • [2.3.1 定义多个对象](#2.3.1 定义多个对象)
      • [2.3.2 Bean的重命名](#2.3.2 Bean的重命名)
    • [2. 4 Bean生效](#2. 4 Bean生效)
  • [3. DI(依赖注入)](#3. DI(依赖注入))
    • [3.1 属性注入](#3.1 属性注入)
    • [3.2 构造方法注入](#3.2 构造方法注入)
    • [3.3 Setter注入](#3.3 Setter注入)
    • [3.4 面试题:三种注入方式的缺点分析?](#3.4 面试题:三种注入方式的缺点分析?)
    • [4.5 @Autowired 注入存在的问题](#4.5 @Autowired 注入存在的问题)
      • [4.5.1 @Primary](#4.5.1 @Primary)
      • [4.5.2 @Qualifier](#4.5.2 @Qualifier)
      • [4.5.3 @Resource](#4.5.3 @Resource)
  • [5. 面试题:常见的注解有哪些?分别是什么作用?](#5. 面试题:常见的注解有哪些?分别是什么作用?)
  • [6. 面试题:`@Autowired` 和 `@resource` 的区别?](#6. 面试题:@Autowired@resource 的区别?)
  • [7. 面试题:什么是IoC?](#7. 面试题:什么是IoC?)

1. Spring、Spring Boot 和 Spring MVC 的关系和区别?(常见面试题)

1.1 Sring

简单来说,Spring 是一个开发应用开发框架(轻量级、一站式、模块化),是包含了众多工具方法的IoC容器。其目的是用于简化企业级应用程序开发。

Spring的主要功能是管理对象,以及对象之间的依赖关系,面向切面编程,数据库事务管理,数据访问,web框架支持等。

但是Spring 具备高度可开放性,并不强制依赖Spring,开发者可以自由选择Spring的部分或者全部,Spring可以无缝继承第三方框架。

1.2 Spring MVC

Spring MVC是Spring 的一个子框架,Spring诞生之后,大家觉得很好用,于是按照MVC模式涉及了一个MVC框架,主要用于开发Web应用和网络接口,所以,Spring MVC是一个Web框架。

Spring MVC 是基于Spring进行开发的,天生的与Spring框架集成。可以让我们更简洁的进行Web层的开发,支持灵活的URL到页面控制器的映射,提供了强大的约定大于配置的契约式编程支持,非常容易与其他视图框架集成。

1.3 Spring Boot

Spring Boot 是对Spring的一个封装,为了简化Spring应有的开发而出现的,中小型企业没有成本研究自己的框架,使用Spring Boot可以更加快速的搭建框架,降低开发成本,让开发人员更加专注Spring应用的开发,而无需过多的关注XML的配置和一些底层的实现。

Spring Boot是一个脚手架,可以快速的集成其他框架进来。

比如想要使用Spring Boot 开发Web项目,只需要引入Spring MVC框架即可,Web开发的工作是Spring MVC 完成的,而不是Spring Boot,想要完成数据访问,只需要引入Mybatis框架即可。

Spring Boot只是辅助简化项目开发的,让开发变的更加简单,甚至不需要额外的Web服务器,直接生成jar包执行即可。

1.4 总结

Spring MVC 和 Spring Boot 都属于Spring ,Spring MVC是基于Spring的一个MVC框架,而Spring Boot 是基于Spring 的一套快速开发整合包。

这三者专注的领域不同,解决的问题也不一样。总的来说,Spring就像一个大家族,有众多衍生产品,但他们的基础都是Spring。

2. IoC

Spring 是一个IOC(控制反转)容器,作为容器,那么就具备最基础的功能:存 & 取。

Spring 容器管理的主要是对象,我们将这些被Spring管理的对象称之为"Bean"。

我们把这些对象交给Spring管理,由Spring来负责对象的创建和销毁。程序只需要告诉Spring,哪些对象需要存,以及如何从Spring中取出对象。

2.1 Bean的存储

有两类注解形式可以实现把对象交给IoC容器管理:

  1. 类注解(五大注解):@Controller、@Service、@Repostory、@Component、@Configuration

  2. 方法注解:@Bean

为什么需要这么多类注解呢?

这个和应用分层是呼应的。让程序员看到类注解之后,就能直接了解到当前类的用途。

2.2 Bean的命名

  1. 五⼤注解存储的bean
    ① 前两位字⺟均为⼤写, bean名称为类名
    ② 其他的为类名⾸字⺟⼩写
    ③ 通过 value属性设置 @Controller(value = "user")
  2. @Bean 注解存储的bean
    ① bean名称为⽅法名
    ②通过name属性设置 @Bean(name = {"u1","user1"})

2.3 方法注解@Bean

方法注解@Bean要配合类注解才能生效。

2.3.1 定义多个对象

java 复制代码
@Configuration
public class UserInfoConfig {
    @Bean
    public UserInfo user1() {
        UserInfo userInfo = new UserInfo(1, "zhangsan", 13);
        return userInfo;
    }
    @Bean
    public UserInfo user2() {
        UserInfo userInfo = new UserInfo(2, "lisi", 13);
        return userInfo;
    }
}

定义多个对象的时候我们就不能通过类型来获取对象了,需要使用Bean的名称来获取。

java 复制代码
@SpringBootApplication
public class SpringIocDemoApplication {

    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(SpringIocDemoApplication.class, args);
        UserInfo bean1 = (UserInfo) context.getBean("user1");
        UserInfo bean2 = (UserInfo) context.getBean("user2");
        System.out.println(bean1);
        System.out.println(bean2);
    }
}

运行结果:

2.3.2 Bean的重命名

通过name属性来对Bean对象进行重命名。

java 复制代码
@Configuration
public class UserInfoConfig {
    //Bean重命名
    @Bean(name = {"zhangsan", "user111"})
    public UserInfo user1() {
        UserInfo userInfo = new UserInfo(1, "zhangsan", 13);
        return userInfo;
    }
}

这样我们就可以通过zhangsan 和 user111任意一个名称来获取到Bean对象。

java 复制代码
@SpringBootApplication
public class SpringIocDemoApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(SpringIocDemoApplication.class, args);
        UserInfo bean = (UserInfo) context.getBean("zhangsan");
        UserInfo bean2 = (UserInfo) context.getBean("user111");
        System.out.println(bean);
        System.out.println(bean2);
     }
}

运行结果:

无论名称是一个还是有多个name{}都可以省略,如`@Bean("zhangsan", "user111")

2. 4 Bean生效

Bean想要生效,需要被Spring扫描到。

默认的扫描范围是Spring Boot启动类所在的包及其子包。

3. DI(依赖注入)

依赖注入是一个过程,是指IOC容器在创建Bean时,去提供运行时所依赖的资源,而资源指的就是对象。

Spring对于依赖注入提供了三种方式:

  1. 属性注入

  2. 构造方法注入

  3. Setter注入

3.1 属性注入

属性注入时使用@Autowired注解实现的。

代码示例:将service类注入到Controller中。

service类代码实现:

java 复制代码
import org.springframework.stereotype.Service;

@Service
public class UserService {
    public void doService() {
        System.out.println("UserService.doService");
    }
}

controller类代码实现:

java 复制代码
import com.bubu.ioc.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {
    //属性注入
    @Autowired
    private UserService userService;

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

获取Controller中的sayHi方法:

java 复制代码
@SpringBootApplication
public class SpringIocDemoApplication {
    public static void main(String[] args) {
        //获取Spring上下⽂对象
        ApplicationContext context =
                SpringApplication.run(SpringIocDemoApplication.class, args);
        //从Spring上下⽂中获取对象
        UserController userController = (UserController)
                context.getBean("userController");
        //使⽤对象
        userController.sayHi();
    }
}
  1. ApplicationContext是什么?
    Application是Spring 上下文。由于我们把对象都交给Spring来进行管理了,所以获取对象要从Spring中来获取,就先得到Spring的上下文。
  2. 上下文是什么?
    比如我们应用进行线程切换的时候,切换前都会把线程的状态信息暂时存储起来,这里的上下文就包括了当前线程的信息,等下次该线程又竞争到CPU上运行的时候,从上下文中拿到线程上次运行的信息。
    这个上下文就是指当前的运行环境,也可以看作是一个容器。容器里面存放了很多的内容,这些内容就是当前运行的环境。

3.2 构造方法注入

构造方法注入是在类的构造方法中实现注入的。

java 复制代码
import com.bubu.ioc.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController5 {
    private UserService userService;
    
    
    @Autowired
    public UserController5(UserService userService) {
        this.userService = userService;
    }

    public void sayHi() {
        System.out.println("hi UserController5");
        userService.doService();
    }
}

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

3.3 Setter注入

Setter注入需要在设置set方法的时候加上@Autowired注解。

java 复制代码
import com.bubu.ioc.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController6 {
    private UserService userService;


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

    public void sayHi() {
        System.out.println("hi UserController5");
        userService.doService();
    }
}

3.4 面试题:三种注入方式的缺点分析?

1. 依赖注入

优点: 简洁,使用方便。

缺点:

①、只能用于IoC容器,如果是非IoC容器不可用,并且只有在使用的时候才会出现NPE(空指针异常)。

②、不能注入一个Final修饰的属性。

2. 构造函数注入(Spring 4.x推荐)

优点:

①、可以注入final修饰的属性。

②、注入的对象不会被修改。

③、依赖对象在使用前一定会被完全初始化,因为依赖是在类的构造方法中执行的,而构造方法是在类加载阶段就会执行的方法。

④、通用性好。构造放是JDK支持的,所以更换任何框架,他都是适用的。

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

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

优点: 方便在类实例之后,重新对该对象进行配置或者注入。

缺点:

①、不能注入Final修饰的属性。

②、注入对象可能会被改变,因为Setter方法可能会被多次调用,就会有被修改的风险。

4.5 @Autowired 注入存在的问题

当同一类型存在多个bean的时候,使用@Autowired注解会存在问题。

java 复制代码
@Configuration
public class UserInfoConfig {
    @Bean
    public UserInfo user1() {
        UserInfo userInfo = new UserInfo(1, "zhangsan", 13);
        return userInfo;
    }
    @Bean
    public UserInfo user2() {
        UserInfo userInfo = new UserInfo(2, "lisi", 13);
        return userInfo;
    }
}
java 复制代码
@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();
    }
}

运行结果:

报错的原因是,非唯一的Bean对象。

解决方案:

  1. @Primary

  2. @Qualifier

  3. @Resource

4.5.1 @Primary

java 复制代码
@Configuration
public class UserInfoConfig {
    @Bean
    @Primary //指定该Bean为默认Bean的实现
    public UserInfo user1() {
        UserInfo userInfo = new UserInfo(1, "zhangsan", 13);
        return userInfo;
    }
    @Bean
    public UserInfo user2() {
        UserInfo userInfo = new UserInfo(2, "lisi", 13);
        return userInfo;
    }
}

4.5.2 @Qualifier

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

java 复制代码
@Controller
@ResponseBody
public class UserController {
    @Autowired
    private UserService userService;

    @Autowired
    @Qualifier("user2")
    private UserInfo userInfo;

    public void sayHi() {
        userService.doService();
        System.out.println(userInfo);
        System.out.println("UserController.sayHi......");
    }
}

4.5.3 @Resource

该注解是按照bean的名称进行注入的。通过name属性指定要注入的bean的名称。

java 复制代码
@Controller
@ResponseBody
public class UserController {
    @Autowired
    private UserService userService;

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

    public void sayHi() {
        userService.doService();
        System.out.println(userInfo);
        System.out.println("UserController.sayHi......");
    }
}

5. 面试题:常见的注解有哪些?分别是什么作用?

web url映射:@RequestMapping

参数接收和接口响应:@RequestParam @RequestBody @ResponseBody

Bean的存储:@Controller, @Service, @Repository, @Component, @Configuration, @Bean'

Bean的获取:@Autowired, @Qualifier, @Resource

6. 面试题:@Autowired@resource 的区别?

@Autowired 是Spring 框架提供的注解,而@Resource是JDK提供的注解。

@Autowired 默认是按照类型注入的,而@Resource 是按照名称注入的。相比于@Autowired来说,@Resource 支持更多的参数设置,例如name设置,根据名称来获取Bean.

Autowired装配顺序:

7. 面试题:什么是IoC?

IoC: 控制反转。也就是说Spring是一个"控制反转"的容器。

也就是获得依赖对象的过程被反转了。当我们需要某个对象时,传统开发模式中需要自己通过new来创建对象,现在不需我们自己进行创建,而是把创建对象的任务交给容器,也就是交给Spring。程序中只需要在使用的时候进行依赖注入就好了。

我们把这个容器称为IoC容器,Spring是一个IoC容器,也被称为Spring容器。

相关推荐
lzj20143 小时前
Spring AI使用知识库增强对话功能
java
大头an3 小时前
Spring 6 & Spring Boot 3新特性:事务管理的革新
java
Ro Jace3 小时前
三国华容道(横刀立马)移动策略
android·java·数据库·人工智能·深度学习·神经网络·游戏
小马爱打代码3 小时前
Java学习笔记:注解详解
java·笔记·学习
我来变强了4 小时前
token无感刷新全流程
java·vue.js
QT 小鲜肉4 小时前
【C++基础与提高】第十一章:面向对象编程进阶——继承与多态
java·linux·开发语言·c++·笔记·qt
aerror4 小时前
将sqlite3的表转成excel表
java·sqlite·excel
仟濹4 小时前
IntelliJ IDEA 快捷键 + 实时模板
java·intellij-idea
洛_尘4 小时前
数据结构--6:优先级队列(堆)
java·数据结构