【JavaEE】-- IoC DI
文章目录
- 1. Spring、Spring Boot 和 Spring MVC 的关系和区别?(常见面试题)
- 1.1 Sring
- 1.2 Spring MVC
- 1.3 Spring Boot
- 1.4 总结
- 2. IoC
- 2.1 Bean的存储
- 2.2 Bean的命名
- 2.3 方法注解@Bean
- 2.3.1 定义多个对象
- 2.3.2 Bean的重命名
- 2. 4 Bean生效
- 3. DI(依赖注入)
- 3.1 属性注入
- 3.2 构造方法注入
- 3.3 Setter注入
- 3.4 面试题:三种注入方式的缺点分析?
- 4.5 @Autowired 注入存在的问题
- 4.5.1 @Primary
- 4.5.2 @Qualifier
- 4.5.3 @Resource
- 5. 面试题:常见的注解有哪些?分别是什么作用?
- 6. 面试题:`@Autowired` 和 `@resource` 的区别?
- 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的命名
- 五⼤注解存储的bean
① 前两位字⺟均为⼤写, bean名称为类名
② 其他的为类名⾸字⺟⼩写
③ 通过 value属性设置 @Controller(value = “user”) - @Bean 注解存储的bean
① bean名称为⽅法名
②通过name属性设置@Bean(name = {"u1","user1"})
2.3 方法注解@Bean
方法注解@Bean要配合类注解才能生效。
2.3.1 定义多个对象
@Configuration
public class UserInfoConfig {@Beanpublic UserInfo user1() {UserInfo userInfo = new UserInfo(1, "zhangsan", 13);return userInfo;}@Beanpublic UserInfo user2() {UserInfo userInfo = new UserInfo(2, "lisi", 13);return userInfo;}
}
定义多个对象的时候我们就不能通过类型来获取对象了,需要使用Bean的名称来获取。
@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对象进行重命名。
@Configuration
public class UserInfoConfig {//Bean重命名@Bean(name = {"zhangsan", "user111"})public UserInfo user1() {UserInfo userInfo = new UserInfo(1, "zhangsan", 13);return userInfo;}
}
这样我们就可以通过zhangsan 和 user111任意一个名称来获取到Bean对象。
@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类代码实现:
import org.springframework.stereotype.Service;@Service
public class UserService {public void doService() {System.out.println("UserService.doService");}
}
controller类代码实现:
import com.bubu.ioc.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;@RestController
public class UserController {//属性注入@Autowiredprivate UserService userService;public void sayHi() {System.out.println("hi UserController");userService.doService();}
}
获取Controller中的sayHi方法:
@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();}
}

- ApplicationContext是什么?
Application是Spring 上下文。由于我们把对象都交给Spring来进行管理了,所以获取对象要从Spring中来获取,就先得到Spring的上下文。- 上下文是什么?
比如我们应用进行线程切换的时候,切换前都会把线程的状态信息暂时存储起来,这里的上下文就包括了当前线程的信息,等下次该线程又竞争到CPU上运行的时候,从上下文中拿到线程上次运行的信息。
这个上下文就是指当前的运行环境,也可以看作是一个容器。容器里面存放了很多的内容,这些内容就是当前运行的环境。
3.2 构造方法注入
构造方法注入是在类的构造方法中实现注入的。
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;@Autowiredpublic UserController5(UserService userService) {this.userService = userService;}public void sayHi() {System.out.println("hi UserController5");userService.doService();}
}
注意:如果类只有一个构造方法,那么@Autowired注解可以省略。如果类中有多个构造方法,那么需要添加上@Autowired来明确指定到底使用哪个构造方法。
3.3 Setter注入
Setter注入需要在设置set方法的时候加上@Autowired注解。
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;@Autowiredpublic 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注解会存在问题。
@Configuration
public class UserInfoConfig {@Beanpublic UserInfo user1() {UserInfo userInfo = new UserInfo(1, "zhangsan", 13);return userInfo;}@Beanpublic UserInfo user2() {UserInfo userInfo = new UserInfo(2, "lisi", 13);return 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();}
}
运行结果:

报错的原因是,非唯一的Bean对象。
解决方案:
1. @Primary
2. @Qualifier
3. @Resource
4.5.1 @Primary
@Configuration
public class UserInfoConfig {@Bean@Primary //指定该Bean为默认Bean的实现public UserInfo user1() {UserInfo userInfo = new UserInfo(1, "zhangsan", 13);return userInfo;}@Beanpublic UserInfo user2() {UserInfo userInfo = new UserInfo(2, "lisi", 13);return userInfo;}
}
4.5.2 @Qualifier
@Qualifier注解不能单独使用,必须配合@Autowired注解使用
@Controller
@ResponseBody
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......");}
}
4.5.3 @Resource
该注解是按照bean的名称进行注入的。通过name属性指定要注入的bean的名称。
@Controller
@ResponseBody
public class UserController {@Autowiredprivate 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容器。
