Spring系列之IOC的理解和分析

开发 架构
对于IOC的理解,主要是停留在概念和几种注入的方式上,虽然知道其生命周期,但是对整个bean管理的宏观角度,理解的不够深刻。

 [[397949]]

根据时间安排,今天主要是对spring中IOC的理解。对于IOC的理解可以从以下几个角度去分析。

什么是IOC?如何使用案例来理解?

  • IOC有哪几种实现方式?
  • IOC的底层实现过程是什么?
  • 根据这几个角度,开始今天的故事,

1 什么是IOC?

对于IOC的理解,主要是停留在概念和几种注入的方式上,虽然知道其生命周期,但是对整个bean管理的宏观角度,理解的不够深刻。

IOC:**控制反转(Inversion of Control)容器,**是一种设计思想。意味着将你设计好的对象交给容器控制。

1.1 什么是依赖注入

这个概念的理解,我准备使用一个案例来表示。如果a类中包含了b类,就说明a类对b类产生了依赖。如一个人需要车,这就说人对车产生了依赖。

  1. class User{  
  2.   Car car;  
  3.   public User(){  
  4.     car=new Car();  
  5.   }  

上面这个案例,可以看到,在User类中,包含了Car类,也就说User类对Car类产生了依赖。

按照传统的方式,User类如果想要使用Car基本上就是在内部new一个新对象即可。但是这样做缺点很大,new的方式也就意味着User和Car产生了紧耦合。不利于大规模使用。于是使用了另外一种方式可以代替。那就是什么时候用到Car,从外部直接传递过来就好。这样的话,耦合性就大大降低了。再看下面这种形式是不是就好很多了。

  1. class User{  
  2.   Car car;  
  3.   public User(Car car){  
  4.     this.car=car;  
  5.   }  

像这样的方式就是依赖注入,也就是把依赖Car注入到了User中。

1.2 什么是控制反转

有了上面依赖注入的概念,再立即控制反转就比较简单了。

  • 谁控制谁:传统方式User是在内部new,现在我们通过依赖注入的方式注入依赖对象Car。现在spring出现了,发明了IOC,IOC里面有一个容器,这些依赖对象全部交给容器去管理。也就是说这些依赖对象的控制权交给了容器。
  • 如何反转:传统方式User是主动去new,这种方式是正转。反转是由容器来帮忙创建及注入依赖对象;

2 依赖注入的几种形式

目前主要有五种注入方式:SET注入,构造器注入,静态工厂,实例工厂。

本文直接使用网上的基本案例来实现。比如UserService依赖UserDao。先把UserDao定义好了,接下来看如何实现注入的。

  1. public class UserDao { 
  2.  public String userLogin() { 
  3.   return "userLogin()方法"
  4.  } 

下面看几种依赖注入的几种实现方式。

2.1 set注入

第一步:XML配置

  1. <?xml version="1.0" encoding="UTF-8"?> 
  2. <beans xmlns="http://www.springframework.org/schema/beans" 
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans 
  5. http://www.springframework.org/schema/beans/spring-beans.xsd"> 
  6.  <bean id="userDao" class="com.xxx.demo.UserDao"></bean> 
  7.  <!-- setter注入 --> 
  8.  <bean id="userService" class="com.xxx.demo.UserService"
  9.         <!--ref是对于外部bean对象引用,与被引用的bean对象的id保持一致--> 
  10.   <property name="userDao" ref="userDao"></property> 
  11.  </bean> 
  12. </beans> 

 

 

第二步:set方式注入

  1. public class UserService { 
  2.     //一定要提供属性的setter方法 
  3.  private UserDao userDao; 
  4.  public void userlogin() { 
  5.   String res=userDao.userLogin(); 
  6.   System.out.println(res); 
  7.  } 
  8.  public void setUserDao(UserDao userDao) { 
  9.   this.userDao = userDao; 
  10.  } 

这种方式简单易操作。

2.2 构造器注入

第一步:XML配置

  1. <?xml version="1.0" encoding="UTF-8"?> 
  2. <beans xmlns="http://www.springframework.org/schema/beans" 
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans 
  5. http://www.springframework.org/schema/beans/spring-beans.xsd"> 
  6.  <bean id="userDao" class="com.xxx.demo.UserDao"></bean> 
  7.  <!-- 构造器注入 --> 
  8.  <bean id="userServiceV2" class="com.xxx.demo.UserServiceV2"
  9.   <constructor-arg index="0" ref="userDao"></constructor-arg> 
  10.   <constructor-arg index="1" value="印度三哥"></constructor-arg> 
  11.  </bean> 
  12. </beans> 

 

 

第二步:构造器注入

  1. public class UserServiceV2 { 
  2.  private UserDao userDao; 
  3.  private String name
  4.  public void userlogin() { 
  5.   String res=userDao.userLogin(); 
  6.   System.out.println(res); 
  7.   System.out.println(name); 
  8.  } 
  9.  public UserServiceV2(UserDao userDao,String name) { 
  10.   super(); 
  11.   this.userDao = userDao; 
  12.   this.name = name
  13.  } 

2.3 静态工厂注入

第一步:XML配置

  1. <?xml version="1.0" encoding="UTF-8"?> 
  2. <beans xmlns="http://www.springframework.org/schema/beans" 
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans 
  5. http://www.springframework.org/schema/beans/spring-beans.xsd"> 
  6.  <!-- 静态工厂注入 --> 
  7.  <bean id="userDao01" class="com.xxx.demo.StaticFactory" factory-method="createuserDao"></bean> 
  8.  <bean id="userService01" class="com.xxx.demo.UserService"
  9.   <property name="userDao" ref="userDao01"></property> 
  10.  </bean> 
  11. </beans> 

 

 

第二步:定义静态工厂

  1. public class StaticFactory { 
  2.  public static UserDao createuserDao(){ 
  3.   return new UserDao(); 
  4.  } 

第三部:静态工厂注入

  1. public class UserService { 
  2.  private UserDao userDao; 
  3.  public void userlogin() { 
  4.   String res=userDao.userLogin(); 
  5.   System.out.println(res); 
  6.  } 
  7.  public void setUserDao(UserDao userDao) { 
  8.   this.userDao = userDao; 
  9.  } 

2.4 实例化工厂

第一步:XML配置

  1. <?xml version="1.0" encoding="UTF-8"?> 
  2. <beans xmlns="http://www.springframework.org/schema/beans" 
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans 
  5. http://www.springframework.org/schema/beans/spring-beans.xsd"> 
  6.  <!-- 实例化工厂 --> 
  7.  <bean id="instanceFactory" class="com.xxx.demo.InstanceFactory"></bean> 
  8.  <bean id="userDao3" factory-bean="instanceFactory" factory-method="createUserDao"></bean> 
  9.  <bean id="userService02" class="com.xxx.demo.UserService"
  10.   <property name="userDao" ref="userDao3"></property> 
  11.  </bean> 
  12. </beans> 

 

 

第二步:工厂注入

  1. public class InstanceFactory { 
  2.  public UserDao createUserDao(){ 
  3.   return new UserDao(); 
  4.  } 

以上就是几种常见的注入方式。在开发中比较常用。知道了IOC的概念和几种实现方式之后,下面主要探讨IOC的底层实现原理。

3 IOC底层实现过程

以上的几种注入方式,可能有个疑问,那就是bean是如何从xml,再到注入类中的呢?看下面这张图

Spring IOC容器初始化的核心过程主要有四个步骤(还有一些如:后置加载器,国际化,事件广播器等一些过程不展开):

  1. Bean定义的定位,Bean 可能定义在XML中,或者一个注解,或者其他形式。这些都被用Resource来定位,读取Resource获取BeanDefinition 注册到 Bean定义注册表中。
  2. 第一次向容器getBean操作会触发Bean的创建过程,实列化一个Bean时 ,根据BeanDefinition中类信息等实列化Bean。
  3. 将实列化的Bean放到单列Bean缓存内。
  4. 此后再次获取向容器getBean就会从缓存中获取。

这张图是核心的过程。这个过程是已经简化了,具体的实现方式要设计到bean的生命周期的管理。安排到下一章节了。spring的核心内容就是aop和ioc,知道了这俩是如何实现的之后,就是核心bean管理的核心实现,最后对配置文件进行介绍。

本文转载自微信公众号「愚公要移山」,可以通过以下二维码关注。转载本文请联系愚公要移山公众号。

 

责任编辑:武晓燕 来源: 愚公要移山
相关推荐

2021-05-06 18:17:52

SpringAOP理解

2022-12-07 08:02:43

Spring流程IOC

2021-03-13 13:57:23

springIOC源码

2024-02-23 10:33:34

SpringBean容器

2021-03-16 08:22:49

SpringIoCAOP

2009-06-22 10:20:01

Spring IoC容

2014-10-22 09:33:10

2024-03-04 11:10:01

2022-02-20 07:28:13

Spring注解用法

2009-06-18 14:45:55

Spring Fram

2022-02-19 07:41:36

Bean注解项目

2012-07-02 15:26:19

Spring架构框架

2022-03-25 00:00:00

Splunk搜索SPL

2021-06-29 07:04:39

SQL数据视图

2021-07-16 06:19:55

SpringIOC腾讯

2020-08-06 00:14:16

Spring IoC依赖注入开发

2021-05-06 07:58:57

Spring BeanIOCAOP

2023-11-15 08:28:13

PythonVTK

2014-10-23 09:40:57

2019-09-09 06:30:06

Springboot程序员开发
点赞
收藏

51CTO技术栈公众号