spring框架(02)——IOC & DI

spring框架

    • 版权声明
    • 二、IOC & DI
      • 1、IOC和DI的理解
      • 2、bean的基本配置
        • (1)基本配置
        • (2)Spring 容器
        • (3)ApplicationContext
        • (4)从IOC容器中获取bean
      • 3、依赖注入
        • (1)属性注入
        • (2)构造方法注入
        • (3)字面值
        • (4)引用其他的bean (ref)
        • (5)注入NULL值
        • (6)注入级联属性
        • (7)注入集合


版权声明

  • 本文原创作者:清风不渡
  • 博客地址:https://blog.csdn.net/WXKKang

二、IOC & DI

1、IOC和DI的理解

  我们先来一起学习一下IOC吧,还记得我们以前是怎么获取资源的吗?我们是不是要首先发起一个请求查找那个资源,然后容器会给我们返回我们所需要查找的资源,但现在不是了,现在是容器主动的将资源推送给它所管理的组件(就像是我们上面的测试类一样),而组件所需要做的事就是选择一种合适的方式来接受资源,IOC的思想就是反转资源获取的方向,这种行为也称为是查找的被动形式
  而DI则是IOC的另一种表达方式:即组件以一些预定好的方式来接收来自于容器的资源注入,相对于IOC而言,这种表述要更加直接一点
  而spring框架的作用就是: 由IOC容器来管理bean,并且为我们提供bean的实例,那么我们就需要完成三个工作——1、怎么样将bean放入IOC容器中?;2、怎么样去创建容器?;3、怎么样从容器中获取bean?现在我们就来一一学习它们

2、bean的基本配置

(1)基本配置

  它的基本配置如下:

<bean id="hello" class="cn.com.demo.HelloWorld">
	<property name="name" value="lucy"></property>
</bean>

  1、id属性:bean的名称,在I0C容器中,bean的名称必须是唯一-的。
  2、如果没有指定id 属性,那么将会用class属性作为bean的名称。
  3、Class属性:类的全名称(包名+类名)

(2)Spring 容器

  在Spring IOC容器读取Bean配置创建Bean实例之前,必须对它进行实例化.只有在容器实例化后,才可以从IOC容器里获取Bean实例并使用.(要获取bean就必须要先实例化IOC容器,然后从容器中获取bean)
Spring提供了两种类型的I0C容器实现:
BeanFactory::IOC容器的基本实现.
ApplicationContext:提供了更多的高级特性.是BeanFactory 的子接口.
BeanFactory是Spring 框架的基础设施,面向Spring 本身; ApplicationContext面向使用Spring 框架的开发者,几乎所有的应用场合都直接使用ApplicationContext 而非底层的BeanFactory。无论使用何种方式,配置文件是相同的.

(3)ApplicationContext

ApplicationContext的主要实现类:
  ClassPathXmlApplicationContext:从类路径下加载配置文件
  FileSystemXmlApplicationContext:从文件系统中加载配置文件
  ConfigurableApplicationContext扩展于ApplicationContext, 新增加两个主要方法: refresh()和close(),让ApplicationContext 具有启动、刷新和关闭上下文的能力
  ApplicationContext在初始化上下文时就实例化所有单例的Bean。 ( 默认spirng容器中的bean都是单例对象)
  WebApplicationContext是专门为WEB应用而准备的,它允许从相对于WEB根目录的路径中完成初始化工作

(4)从IOC容器中获取bean

  调用ApplicationContext 的getBean() 方法
  Getbean()方法的参数:
  String:根据配置文件中的ID属性来获取bean
  Class:根据对象的类型来获取bean。注意:如果只指定要返回的Bean的类型就想从IOC容器中取得Bean的前提是该类型的Bean在IOC容器中只有一个

3、依赖注入

  所谓依赖注入,是指通过配置文件,构造方法等向bean的属性中注入值。在Spring中依赖注入有三种方式,它们是通过属性注入、通过构造方法注入、通过工厂方法注入

(1)属性注入

  属性注入即通过setter 方法注入Bean的属性值或依赖的对象
  属性注入使用 元素,使用name 属性指定Bean 的属性名称,value 属性或 子节点指定属性值。属性注入是实际应用中最常用的注入方式,如下面的代码:

<bean id="hello" class="cn.com.demo.HelloWorld">
	<property name="name" value="lucy"></property>
</bean>

(2)构造方法注入

  既然是要通过构造方法注入,那么这个类中就必须要有带参构造方法,如下:

package cn.com.demo;

public class HelloWorld {
	private String name;

	public HelloWorld() {
		super();
	}
	//带参构造发方法
	public HelloWorld(String name) {
		super();
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	@Override
	public String toString() {
		return "HelloWorld [name=" + name + "]";
	}

	public void hello(){
		System.out.println("hello world!!");
	}
}

  有了带参构造函数之后我们就可以通过构造函数注入属性的值了,如下:

<!-- 通过构造方法注入属性值 -->
<bean id="helloWorld" class="cn.com.demo.HelloWorld">
	<constructor-arg value="tom"></constructor-arg>
</bean>

  注意:在配置文件中的constructor-arg节点的顺序要和构造方法中参数的顺序一致(设置的参数个数与构造方法中的参数数量一致)
  并且,我们还可以通过index,参数类型及参数名称来匹配输入参数,例如现在有一个学生类,如下:

package cn.com.demo;

public class Student {
	private String name;
	private String gender;
	private Integer age;
	public Student() {
		super();
	}
	public Student(String name, String gender, Integer age) {
		super();
		this.name = name;
		this.gender = gender;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", gender=" + gender + ", age=" + age + "]";
	}
}

  那么我们就可以按照以上三种方式来通过构造方式来给属性注入值了,如下:
spring框架(02)——IOC & DI_第1张图片
  注意: 按照类型来匹配构造方法的参数,不同数据类型可以进行分辩,但是同种类型的参数将无法分辨。例如上例中,可以将Integer类型的参数放在任何一个位置都可以分辨出来,但是两个String类型的参数将无法分辨,所以说在本例中通过类型匹配属性参数是行不通的!!!

(3)字面值

  如果在使用过程中有数据的值为特殊字符(如”<“或”>“)的时候该怎么办呢?这就需要用到字面值了
  字面值: 可用字符串表示的值,可以通过元素标签或value 属性进行注入。基本数据类型及其封装类、String 等类型都可以采取字面值注入的方式。
  若字面值中包含特殊字符,可以使用 把字面值包裹起来,例如:

<!-- 字面值示例-->
<bean id="car4" class="cn.com.springdemo.beans.Car">
	<!--放入到value属性中的字面值-->
	<constructor-arg value="中国" name="corp"></constructor-arg>
	<constructor-arg name="price">
		<!--放入到value节点中的字面值-->
		<value>4</value>
	</constructor-arg>
	<constructor-arg name="brand">
		<!--包含特殊字符的字面值需要放入到<![CDATA[]]>-->
		<value><![CDATA[<Auto>]]></value>
	</constructor-arg>
</bean

(4)引用其他的bean (ref)

  组成应用程序的Bean 经常需要相互协作以完成应用程序的功能(例如某个人拥有一辆车),要使Bean 能够相互访问,就必须在Bean配置文件中指定对Bean的引用。
  在Bean的配置文件中,可以通过 元素或ref属性为Bean 的属性或构造器.参数指定对Bean的引用,如下:

<!--第一种方式 -->
<bean id="p2" class="cn.com.springdemo.beans.Person">
	<property name="name" value="张三"></property>
	<!--通过属性来应用其他bean-
	<property name="car">
		<ref bean="car4"/>
	</property>
</bean>

<!--第二种方式 -->
<bean id="p2" class="cn.com.springdemo.beans.Person">
	<property name="name" value="张三"></property>
	<!--通过属性来应用其他bean-
	<property name="car" ref="car4"></property>
</bean>

  遇到这样的情况,我们也可以在属性或构造器里包含Bean 的声明,这样的Bean 称为内部Bean。 当Bean实例仅仅给–个特定的属性使用时,可以将其声明为内部Bean。内部Bean声明直接包含在 元素里,不需要设置任何id 或name属性。内部Bean不能使用在任何其他地方,例如:

<!--内部bean -->
<bean id="p3" class="cn.com.springdemo.beans.Person">
	<property name="name" value="张三"></property>
	<!--通过属性来应用其他bean -->
	<property name="car">
		<bean class="cn.com.springdemo.beans.Car">
			<constructor-arg value="大中国" index="1"></constructor-arg>
			<constructor-arg value="红旗" index="0"></ constructor-arg>
			<constructor-arg value="40000" index="2"></constructor-arg>
		</bean>
	</property>
</bean>

(5)注入NULL值

  当我们需要为bean中的元素注入NULL值得时候该怎么做呢?可以使用专用的 元素标签为Bean的字符串或其它对象类型的属性注入null值,如下:

<property name="name">
	<null></null>
</property>

(6)注入级联属性

  我们还会遇到一种情况,那就是注入级联属性,例如我们需要设置某个人拥有的某辆车的属性,这种情况下我们怎样完成呢?如下:

<bean id="p2" class="cn.com.springdemo.beans.Person">
	<property name="name">
		<null></nu1l>
	</property>
	<!-通过属性来应用其他bean--->
	<property name="car">
		<ref bean="car3" />
	</property>
	<!--注入级联属性-->
	<property name="car.price" value="40"></property>
</bean>

  但是注入级联属性有一个前提就是为级联属性赋值的时候首先必须初始化这个对象(例如car),否则将会报异常

(7)注入集合

  同样,我们也可以在IOC容器中为bean注入集合,例如List,Map,Set,properties集合等,那么我们需要怎样去注入呢?例如一个土豪他有很多辆车,请看下面:
  1、注入List
配置java.util.List 类型的属性,需要指定 标签, 在标签里包含一些元素.这些标签可以通过 指定简单的常量值,通过 指定对其他Bean 的引用.通过指定内置Bean定义.通过 指定空元素.甚至可以内嵌其他集合,数组的定义和List一样,都使用,示例如下:

<bean id="th1" class="cn.com.springdemo.beans.TuHao">
<property name="name" value="土豪一号"></property>
<!--注入list集合-->
<property name="list">
	<list>
		<ref bean="car1"/>
		<bean class="cn.com.springdemo.beans.Car">
			<constructor-arg value="大中国" index="1"></constructor-arg>
			<constructor-arg value="红旗" index="0"></constructor-arg>
			<constructor-arg value="40000" index="2"></ constructor-arg>
		</bean>
	</list>
</property>
</bean>

  通过上面的代码我们可以看到,我们可以通过两种方式往List里面注入值,第一种就是通过标签,第二种则是通过内置bean,这样我们就实现了注入List
  2、注入map
  同样,我们也可以通过标签和标签注入map,示例如下:

<!--注入map -->
<bean id="th2" class="cn.com.springdemo.beans.TuHao">
	<property name="name" value="土豪二号"></property>
	<!--注入map集合-->
	<property name="map">
		<map>
			<entry key="car1" value-ref="car1" />
			<entry key="car2" value-ref="car2" />
		</map>
	</property>
</bean>

  3、注入properties
  我们可以使用 定义java.util.Properties, 该标签使用多个 作为子标签.每个标签必须定义key属性,示例如下:

<!--注入properties -->
<bean id="datasource" class="cn.com.springdemo.beans.DataSource ">
	<property name="propertie">
		<props>
			<prop key="driver">com.mysql.jdbc.Driver</prop>
			<prop key="urL">mysql:jdbc//127.0.0.1:3306/demo
			<prop key="username">root</prop>
			<prop key="password">123456</prop>
		</props>
	</property>
</bean>

  啊哈,IOC容器的各种注入终于记录完了,继续加油

你可能感兴趣的:(spring,spring)