Spring学习记录(二)——初步体验IoC

2018.4.12

仅为个人理解 不足之处欢迎指正~

什么是IoC?

IoC即Inversion of Control “控制反转”是Spring的基础

简单的理解是把“创建对象的权利”交由Spring

仅用语言很难形容 我们在例子中逐渐理解这一思想


了解控制反转 需要了解依赖倒置原则

以下内容部分参考知乎用户 Sevenvidia的回答~

依赖倒置原则(Dependency Inversion Principle)

什么是依赖倒置原则?

假如我们现在需要设计一辆汽车 我们按照以下顺序进行设计:

1.先设计轮胎

2.根据轮胎大小设计底盘

3.根据底盘设计车身

4.根据车身设计整个汽车


现在我们得到了这样一个依赖关系:

汽车依赖车身 车身依赖底盘 底盘依赖轮子

用箭头表示依赖关系:

汽车—>车身—>底盘—>轮胎

现在我们使用代码来还原这样一个设计过程 并以最终完成一辆车为目的:


package pojo;

public class Tire //轮胎
{
	private int size;
	
	Tire()
	{
		this.size=30; //轮胎尺寸默认为30
	}
}
package pojo;

public class Bottom //底盘
{
	private Tire tire;
	Bottom()
	{
		this.tire=new Tire();
	}
}

package pojo;

public class Framework //车身
{
	private Bottom bottom;
	Framework()
	{
		this.bottom=new Bottom();
	}
}
package pojo;

public class Car 
{
	private Framework framework;
	
	Car()
	{
		this.framework=new Framework();
	}
	
	public void run()
	{
		System.out.println("设计完成!");
	}
}

同时 要初始化这辆车 测试类为:

package pojo;

public class Test 
{
	public static void main(String args[])
	{
		Car mycar=new Car();
		mycar.run();
	}
}

而现在假如我们需要改动轮胎类 将尺寸从默认改为动态

我们看看需要对所有代码进行多少改动

1.

2.

3.

4.

5.

由此我们可以看到 仅仅为了修改一个轮胎的参数 却需要修改所有的上层类的构造函数 这对于一个较大的项目来说几乎是不可能的

虽然在这个例子中 我们修改的是最底层的轮胎类 才导致了上层所有类的修改

但是在实际项目中 有的类可能是成百上千个类的底层

同时 有的顶层类可能需要一层一层的依赖关系 这样一来即使不修改最底层的类 而是修改中间层的类 也很难做到

所以我们需要进行控制反转

而实现这一操作我们需要“依赖注入

依赖注入即把底层类作为参数传入上层类 实现上层类对下层类的控制 而不是下层控制着上层

我们使用这一思想重新进行设计车辆的过程:

1.先设计汽车的大概样子

2.根据汽车设计车身

3.根据车身设计底盘

4.根据底盘设计轮胎


现在我们得到了这样一个依赖关系:

轮子依赖底盘 底盘依赖车身 车身依赖汽车

用箭头表示依赖关系:

轮胎—>底盘—>车身—>汽车

现在我们使用代码来还原这样一个设计过程 并以最终完成一辆车为目的:


package pojo;

public class Tire //轮胎
{
	private int size;
	
	Tire()
	{
		this.size=30; //默认为30
	}
}

package pojo;

public class Bottom //底盘
{
	private Tire tire;
	Bottom(Tire tire)
	{
		this.tire=tire;
	}
}
package pojo;

public class Framework //车身
{
	private Bottom bottom;
	Framework(Bottom bottom)
	{
		this.bottom=bottom;
	}
}
package pojo;

public class Car 
{
	private Framework framework;
	
	Car(Framework framework)
	{
		this.framework=framework;
	}
	
	public void run()
	{
		System.out.println("设计完成!");
	}
}

同时测试类也需要改动为:

package pojo;

public class Test 
{
	public static void main(String args[])
	{
		Tire tire=new Tire();
		Bottom bottom=new Bottom(tire);
		Framework framework=new Framework(bottom);
		Car mycar=new Car(framework);
		mycar.run();
	}
}

此时我们再进行刚才的“将轮胎尺寸改为动态”操作 看看需要进行多少改动:

1.

2.

我们可以看到 只需要修改轮胎类而不用修改其他任何上层类

这显然更易于维护

值得一提的是:

   在这里我们采用的是 “构造函数传入” 这一方式进行的依赖注入

    还有另外两种方法“ Setter传递”与“接口传递”将在以后提到

但同时我们又发现了新的问题:


因为使用了依赖注入 在初始化的过程中不可避免的将写大量的new

而Spring很好的帮我们解决了这个问题

我们依然以汽车 轮胎这个例子来看看Spring的便捷之处


新建项目并编写pojo类


为了方便演示 我们在每个组件都加入了“组件名”这一属性

package com.tzy.pojo;

public class Tire 
{
	private int size;
	private String tirename;
	
	public void setSize(int size)
	{
		this.size=size;
	}
	
	public int getSize()
	{
		return size;
	}
	
	public void setTirename(String name)
	{
		this.tirename=name;
	}
	public String getTirename()
	{
		return tirename;
	}
}
package com.tzy.pojo;

public class Bottom 
{
	private Tire tire;
	private String bottomname;
	
	public void setTire(Tire tire)
	{
		this.tire=tire;
	}
	
	public Tire getTire()
	{
		return tire;
	}
	
	public void setBottomname(String name)
	{
		this.bottomname=name;
	}
	public String getBottomname()
	{
		return bottomname;
	}
}

package com.tzy.pojo;

public class Framework 
{
	private Bottom bottom;
	private String frameworkname;
	
	public void setBottom(Bottom bottom)
	{
		this.bottom=bottom;
	}
	
	public Bottom getBottom()
	{
		return bottom;
	}
	public void setFrameworkname(String name)
	{
		this.frameworkname=name;
	}
	public String getFrameworkname()
	{
		return frameworkname;
	}
}
package com.tzy.pojo;

public class Car 
{
	private Framework framework;
	private String carname;
	
	public void setFramework(Framework framework)
	{
		this.framework=framework;
	}
	
	public Framework getFramework()
	{
		return framework;
	}
	
	public void setCarname(String name)
	{
		this.carname=name;
	}
	public String getCarname()
	{
		return carname;
	}
	
	public void run()
	{
		System.out.println("生产了一辆汽车");
	}
}

需要注意的是:在这些类中用到是依赖注入的第二个方法“Setter传递”


编写applicationContext.xml

在src目录下新建applicationContext.xml

这是Spring的核心配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
   http://www.springframework.org/schema/beans 
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/aop 
   http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
   http://www.springframework.org/schema/tx 
   http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
   http://www.springframework.org/schema/context      
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">
      
   <bean name="car" class="com.tzy.pojo.Car">
   		<property name="framework" ref="framework"/>
   </bean>
   
    <bean id="framework" class="com.tzy.pojo.Framework">
    	<property name="bottom" ref="bottom"/>
   </bean>
   
     <bean id="bottom" class="com.tzy.pojo.Bottom">
     	<property name="tire" ref="tire"/>
   </bean>
     <bean id="tire" class="com.tzy.pojo.Tire">
     	<property name="size" value="30"/>
   </bean>
	
  </beans>

接下来解释一下配置文件中的部分问题

1.什么是bean name? 

    

name可以自己命名 class则指向pojo类 意思就是告诉Spring:这是一个类

这一句的作用是将Car这个类“装配”到Spring中

2.bean id 与bean name有什么区别?

大概说一下这两种用法的不同:
1)id属性在IoC容器中必须是唯一的
    而name属性可以相同 后一个出现的name会覆盖之前出现的同名的bean
2)id的命名遵循XML对id的约束
    必须以字母开始 可以使用字母、数字、连字符、下划线、句号和冒号

 所以如果bean的名称中含有特殊字符 使用name属性

3.property name 是什么 ref与value又有什么区别?


在上面我们知道 Tire类中有tirename和size这两个属性

而property name 则是对属性配置默认值 这里的“size”必须是类中所包含的属性

这一句代码的意思就是 将轮胎的尺寸默认设为30

以后产生的每一个轮胎 都将默认为这个尺寸


那么这个ref就很好理解了

Bottom类中有tire这个属性 而tire也是一个类 并不是一个值 所以使用ref来指向一个类

需要注意的是 ref后跟的对象必须也在spring中被装配 同时装配名要与ref后跟的名字相同


编写测试类


package com.tzy.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.tzy.pojo.*;

public class TestSpring 
{
	public static void main(String args[])
	{
		ApplicationContext context=new ClassPathXmlApplicationContext
				(new String[]{"applicationContext.xml"});
		Car mycar=(Car)context.getBean("car");
		mycar.run();
		System.out.println("轮胎的尺寸为:"+mycar.getFramework().getBottom().getTire().getSize());
	}
}

运行结果:


在这里我们看到:

只用了一行代码就创建了一个Car实例:


这里getBean中的"car" 必须是xml中bean id或bean name中所配置的名称

现在我们随意添加车身属性 并修改轮胎的尺寸:


添加一行测试代码:

System.out.println("车身的名字为:"+mycar.getFramework().getFrameworkname());

运行:


我们只需要修改一个xml文档就可以实现对任意层面的组件的修改



总结:

 Spring的IoC容器就像一个不需要我们来掌握细节的“工厂”

我们只是工厂的“客户” 我们对工厂提出一个要求:

我要一个Car实例 工厂就给我们一个Car实例

而其中无论有多少层的依赖关系 都不是我们需要管的了


谢谢~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值