控制反转(IoC)是什么?
文章目录
- 二、IoC是什么?
- 三、具体程序开发举例
- 四、控制反转(IoC)有什么用?
- 五、Bean的存储
- getBean
- getBean传参注意
- 小驼峰
- 两个连续大写字母开头的类名
- 1.1@Controller(控制器存储)
- 1.2@Service(服务存储)
- 1.3@Repository(仓库存储)
- 1.4@Component(组件存储)
- 1.5@Configuration(配置存储)
- 五种类注解的联系
- 方法注解@Bean
- 当有多个构造方法时,需要使用类名来获取bean对象。
- 当构造方法有参数时,需要创建参数对应类型的方法
- 在这里插入图片描述
学习Spring框架的小伙伴肯定都知道Spring框架的核心是IoC容器和AOP模块。
也都听说过 Spring是包含众多工具方法的IoC容器。
IoC容器是Spring框架的底层基础,负责管理对象的创建和对象依赖关系的维护
IoC是一种思想,而DI就是实现这个思想的一种方法。
那么本文就带大家来了解什么是IoC
二、IoC是什么?
Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。
在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制,对于spring框架来说,就是由Spring来负责控制对象的生命周期和对象间的关系。
在开发中的表现就是: 当需要一个对象时,不再自己通过new来创建对象,而是把创建对象的任务交给容器,在程序中只需要依赖 注入(DI)。这个容器就成为IoC容器。
三、具体程序开发举例
现在有这样的需求:造一辆车
我们根据需求来梳理思路:
我们先设计轮子(Tire),然后根据轮子的大小来设计地盘(Bottom),然后根据底盘设计车身(Framework),然后再由车身设计出整个汽车。
这里就出现了一个依赖关系:
汽车依赖车身,车身依赖底盘,底盘依赖轮子
public class Main { public static void main(String[] args) { Car car = new Car(); car.run(); } } public class Car { private Framework framework; public Car() { framework = new Framework(); System.out.println("car init ...."); } public void run(){ System.out.println("car run ...."); } } public class Framework { private Bottom bottom; public Framework() { bottom = new Bottom(); System.out.println("framework init...."); } } public class Bottom { private Tire tire; public Bottom() { tire = new Tire(); System.out.println("bottom init...."); } } public class Tire { private int size = 17; public Tire( ){ System.out.println("Tire init...."); } }运行程序
当车轮的尺寸需要随着不同的需求而变更时,那么底盘,车身,汽车都要受到波动。
这样的设计,导致耦合太高,当一部分的代码需求变更时,会影响其他很多代码,增加了改动的成本
那么如何解决呢?
我们尝试换⼀种思路, 我们先设计汽⻋的⼤概样⼦,然后根据汽⻋的样⼦来设计⻋⾝,根据⻋⾝来设计
底盘,最后根据底盘来设计轮⼦. 这时候,依赖关系就倒置过来了:轮⼦依赖底盘, 底盘依赖⻋⾝,
⻋⾝依赖汽⻋
我们可以尝试不在每个类中⾃⼰创建下级类,如果⾃⼰创建下级类就会出现当下级类发⽣改变操作,
⾃⼰也要跟着修改.
此时,我们只需要将原来由⾃⼰创建的下级类,改为传递的⽅式(也就是注⼊的⽅式),因为我们不
需要在当前类中创建下级类了,所以下级类即使发⽣变化(创建或减少参数),当前类本⾝也⽆需修
改任何代码,这样就完成了程序的解耦.
public class Main { public static void main(String[] args) { Tire tire = new Tire(18,"red"); Bottom bottom = new Bottom(tire); Framework framework = new Framework(bottom); Car car = new Car(framework); car.run(); } }这样做以后,我们传入的都是对象,当一个对象属性发生改变时,不会影响其他部分的正常运行。
达到解耦合的作用
我们发现了⼀个规律,通⽤程序的实现代码,类的创建顺序是反的,传统代码是 Car 控制并创建了Framework,Framework 创建并创建了 Bottom,依次往下,⽽改进之后的控制权发生的反转,不再是使⽤⽅对象创建并控制依赖对象了,⽽是把依赖对象注⼊将当前对象中,依赖对象的控制权不再由当前类控制了.
这样的话, 即使依赖类发⽣任何改变,当前类都是不受影响的,这就是典型的控制反转,也就是 IoC 的实现思想。
四、控制反转(IoC)有什么用?
- 资源集中管理: IoC容器会帮我们管理⼀些资源(对象等), 我们需要使⽤时, 只需要从IoC容器中去取就可以了
- 解耦合:我们在创建实例的时候不需要了解其中的细节, 降低了使⽤资源双⽅的依赖程度
看到这是不是还有点懵,还没真正的搞懂什么是IoC,那么接下来就会使用来让你真正的认识IoC。
五、Bean的存储
在这一部分,会真正的使用IoC,来对IoC有一个深刻且全面的认识。
首先我们先搞清楚概念Bean是什么东西?
根据Bing搜索:
简而言之Bean就是容器内的对象。
这里的注解就是告诉Spring这里的内容已经放置到容器内了
要将创建对象的控制权交给Spring,就要事先声明给Spring哪些是需要进行控制的。
那么实现方式有两种
- 类注解:@Controller、@Service、@Repository、@Component、@Configuration
- 方法注解:@Bean
getBean
ApplicationContext context = SpringApplication.run(IoCApplication.class, args);
这是启动类的代码,这里返回的ApplicationContext就是Spring的运行环境。
这里的context就相当于是一个容器了,那么要如何从容器中拿到对象呢?
这里就要使用getBean这个方法了。
getBean方法括号内常用的传参方式有三种
举例如下
这是在后面要讲解的@Controller注解
@Controller public class Usercontroller { public void DoController() { System.out.println("Do Controller...."); } }@SpringBootApplication public class IoCApplication { public static void main(String[] args) { ApplicationContext context = SpringApplication.run(IoCApplication.class, args); Usercontroller bean = context.getBean(Usercontroller.class); bean.DoController(); } }getBean传参注意
这里要注意,使用名称来获取时,使用小驼峰的命名规范。
当类名前两个字母是连续大写时,就不需要变成小驼峰。
如果需要调用方法,这里需要转型
小驼峰
这有两个注意点:
2. 类型转换
在使用类名获取bean对象时,我们还要进行类型的转换!
两个连续大写字母开头的类名
这时就不需要变成小驼峰的形式。
这是bean的名称的内部实现方式的源码
1.1@Controller(控制器存储)
@Controller public class Usercontroller { public void DoController() { System.out.println("Do Controller...."); } }@SpringBootApplication public class IoCApplication { public static void main(String[] args) { ApplicationContext context = SpringApplication.run(IoCApplication.class, args); Usercontroller bean = context.getBean(Usercontroller.class); bean.DoController(); } }在平常,我们调用对象的方法,首先需要先创建对象,然后再调用对应的方法。
现在我们
1.2@Service(服务存储)
@Service public class UserService { public void DoService(){ System.out.println("do service..."); } }@SpringBootApplication public class IoCApplication { public static void main(String[] args) { ApplicationContext context = SpringApplication.run(IoCApplication.class, args); //从context中获取对象 // Usercontroller bean = context.getBean(Usercontroller.class); // bean.DoController(); UserService bean1 = context.getBean(UserService.class); bean1.DoService(); } }getBean方法括号内常用的传参方式有三种
通过类型来获取 通过名称来获取 通过类型和名称一同获取
这里要注意,使用名称来获取时,使用小驼峰的命名规范。
当类名前两个字母是连续大写时,就不需要变成小驼峰。
如果需要调用方法,这里需要转型
1.3@Repository(仓库存储)
@Repository public class UserRepository { public void DoRepository() { System.out.println("Do Repository..."); } }@SpringBootApplication public class IoCApplication { public static void main(String[] args) { ApplicationContext context = SpringApplication.run(IoCApplication.class, args); UserRepository bean2 = context.getBean(UserRepository.class); bean2.DoRepository(); } }1.4@Component(组件存储)
@Component public class UserComponent { public void DoComponent(){ System.out.println("Do Component"); } }@SpringBootApplication public class IoCApplication { public static void main(String[] args) { ApplicationContext context = SpringApplication.run(IoCApplication.class, args); UserComponent bean3 = context.getBean(UserComponent.class); bean3.DoComponent(); } }1.5@Configuration(配置存储)
@Configuration public class UserConfiguration { public void DoConfiguration() { System.out.println("UserConfiguration"); } }@SpringBootApplication public class IoCApplication { public static void main(String[] args) { ApplicationContext context = SpringApplication.run(IoCApplication.class, args); UserConfiguration bean4 = context.getBean(UserConfiguration.class); bean4.DoConfiguration(); } }五种类注解的联系
查看@Controller / @Service / @Repository / @Configuration的源码发现,这些注解都包含一个@Component的注解,说明四个注解都是@Component的子类。
方法注解@Bean
@Bean必须搭配类注解才能使用
public static void main(String[] args) { ApplicationContext context = SpringApplication.run(IoCApplication.class, args); UserInfo bean = context.getBean(UserInfo.class); System.out.println(bean); }@Data public class UserInfo { private Integer id; private String name; private Integer age; }public class BeanConfig { @Bean public UserInfo getUserInfo() { UserInfo userInfo = new UserInfo(); userInfo.setAge(18); userInfo.setId(11); userInfo.setName("张三"); return userInfo; } }我们运行,出现如下报错,这是因为如果我们要使用@Bean时, 必须要在类前,也就是在BeanConfig这部分代码中,提前声明告诉Spring这里面有需要管理的对象。
此时在BeanConfig中加入@Configuration注解,就运行成功了。
当有多个构造方法时,需要使用类名来获取bean对象。
如上代码,有两个构造方法,此时再用类型传参就会报错
这时就需要使用类名来传参
UserInfo userInfo = (UserInfo)context.getBean("getUserInfo"); System.out.println(userInfo);这时就能获取到UserInfo对象了。
当构造方法有参数时,需要创建参数对应类型的方法
这时就需要有参数的方法getUserInfo时,就需要再使用@Bean来创建一个String类型的name对象。

以上就是本文所有内容,如果对你有帮助的话,点赞收藏支持一下吧!💞💞💞
























