Spring的核心中IOC、DI

本文深入解析Spring框架中的IoC(控制反转)与DI(依赖注入)概念,阐述其设计思想与工作原理。详细介绍了Bean的实例化、作用域、生命周期及属性注入方式,包括构造方法注入和setter方法注入,同时探讨了SpEL表达式和集合属性的注入方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

IOC的概念:

Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。即将对象的创建权交给了Spring容器管理;

DI的概念:

DI—Dependency Injection,即“依赖注入”组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。

  理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,那我们来深入分析一下:

  ●谁依赖于谁:当然是应用程序依赖于IoC容器

  ●为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源

  ●谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象

  ●注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)

 IOC容器装配Bean:

 1.三种实例化Bean的方式:

*使用类构造器实例化(默认无参数)

实例1,创建一个类Bean1,然后配置applicationContext.xml文件,配置文件一般命名为apllicationContext.xml,代码如下:

package com.spring.Bean;
/**
 * 默认构造方法实例化
 * @author 哎呦不错呦
 *
 */
public class Bean1 {
	public Bean1() {
		
	}
}

下面在applicationContext.xml中进行配置;代码如下:

<!-- 默认情况下使用无参的构造方法 -->
	 <bean id="bean1" class="com.spring.Bean.Bean1"></bean>

*使用静态工厂实例化(简单工厂模式)

实例2:创建一个java类Bean2,然后在创建一个工厂类Bean2Factory,在工厂类中创建一个静态方法,调用静态方法返回Bean2对象。下面是代码:

package com.spring.Bean;
/**
 * 静态工厂实例化
 * @author 哎呦不错呦
 *
 */
public class Bean2 {

}

package com.spring.Bean;
public class Bean2Factory {
public static Bean2 getBean2() {
	System.out.println("你使用静态工厂调用了Bean2的方法");
	return new Bean2();	
}
}

接下来在配置applicationContext.xml文件。在xml文件中配置工厂类,并配置好factory-mothod方法;

<!-- 使用静态工厂实例化 -->
 <bean id="bean2" class="com.spring.Bean.Bean2Factory" factory-method="getBean2"></bean>  

*使用实例工厂方法实例化(工厂方法模式)

实例3:创建一个类Bean3,然后在创建一个工厂类Bean3Factory,编写方法返回Bean3对象,代码如下:

 

package com.spring.Bean;
/**
 * 实例工厂实例化
 * @author 哎呦不错呦
 *
 */
public class Bean3 {

}


package com.spring.Bean;
/**
 * Bean3Factory工厂类
 * @author 哎呦不错呦
 *
 */
public class Bean3Factory {
public Bean3 getBean3() {
	System.out.println("使用了实例工厂实例化方法");
	return new Bean3();
}
}

接下来再配置applicationContext.xml配置文件:

<!-- 使用实例工厂实例化 -->
<bean id="bean3" factory-bean="bean3Factory" factory-method="getBean3"></bean>
<bean id="bean3Factory" class="com.spring.Bean.Bean3Factory" ></bean>

 最后是以上3种方法的测试类代码:

package com.spring.Bean;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * 测试
 * @author 哎呦不错呦
 *
 */
public class SpringTest {
/**
 * 无参构造方法实例化
 */
	@Test
	public void demo1() {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
		Bean1 bean1 = (Bean1) applicationContext.getBean("bean1");
		System.out.println(bean1);
	}	
/**
 * 静态工厂实例化
 */
	@Test
	public void demo2() {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
		Bean2 bean2 = (Bean2) applicationContext.getBean("bean2");
		System.out.println(bean2);
	}	
/**
 * 实例工厂实例化
 */	
	@Test
	public void demo3() {
		ApplicationContext applicationContext =  new ClassPathXmlApplicationContext("applicationContext.xml");
		Bean3 bean3 = (Bean3) applicationContext.getBean("bean3");
		System.out.println(bean3);
	}
}

Bean的作用域:(如下表说明)

类别

说明

singleton

在Spring IoC容器中仅存在一个Bean实例,Bean以单例方式存在

prototype

每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时 ,相当于执行new XxxBean()

request

每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境

session

同一个HTTP Session 共享一个Bean,不同Session使用不同Bean,仅适用于WebApplicationContext 环境

globalSession

一般用于Porlet应用环境,该作用域仅适用于WebApplicationContext 环境

 Spring容器中Bean的声明周期:

1.instantiate bean对象实例化

2.populate properties 封装属性

3.如果Bean实现BeanNameAware 执行 setBeanName

4.如果Bean实现BeanFactoryAware 或者 ApplicationContextAware 设置工厂 setBeanFactory 或者上下文对象 setApplicationContext

5.如果存在类实现 BeanPostProcessor(后处理Bean) ,执行postProcessBeforeInitialization

6.如果Bean实现InitializingBean 执行 afterPropertiesSet

7.调用<bean init-method="init"> 指定初始化方法 init

8.如果存在类实现 BeanPostProcessor(处理Bean) ,执行postProcessAfterInitialization

9.执行业务处理

10.如果Bean实现 DisposableBean 执行 destroy

11.调用<bean destroy-method="customerDestroy"> 指定销毁方法 customerDestroy

注意:主要记住第5步及第8步;

 Bean的属性注入:(Spring支持构造方法注入和setter方法注入)

1.构造器注入:

 实例4:创建一个类Car,代码如下:

package com.study.SpringDemo5;
public class Car {
	private String name;
	private Double price;
	public Car(String name, Double price) {
		super();
		this.name = name;
		this.price = price;
	}
	public Car() {
		super();
		// TODO Auto-generated constructor stub
	}
	@Override
	public String toString() {//当创建对象时,自动调用此方法打印
		return "Car [name=" + name + ", price=" + price + "]";
	}
	
}

然后再配置applicationContext.xml文件;代码如下:

<bean id="car" class="com.study.SpringDemo5.Car">
		 <constructor-arg name="name" value="奥迪"></constructor-arg>
		<constructor-arg name="price" value="500000"></constructor-arg>
		<!-- 如果构造器注入属性的时候,参数为一个对象时可以使用ref属性 -->
		<!-- <constructor-arg index="0" ref="car2" ></constructor-arg> -->
		<constructor-arg index="0" value="别克" type="String"></constructor-arg>
		<constructor-arg index="1" value="150000" type="Double"></constructor-arg>
</bean>
<!-- setter方法的注入 -->
	<bean id="car2" class="com.study.SpringDemo5.Car2">
		<property>标签中name就是属性名称,value是普通的属性的值,ref:引用其它对象
		<property name="name" value="丰田"></property>
		<property name="price" value="180000"></property>
	</bean> 

2.setter方法注入

实例5:创建一个类Car2,下面是实例代码:

package com.study.SpringDemo5;
public class Car2 {
	private String name;
	private Double price;
	public void setName(String name) {
		this.name = name;
	}
	public void setPrice(Double price) {
		this.price = price;
	}
	@Override
	//加载类的对象时方法自动执行
	public String toString() {
		return "Car2 [name=" + name + ", price=" + price + "]";
	}	
}

接下来再配置applcationContext.xml文件。代码如下:

<!-- setter方法的注入 -->
	<!-- <bean id="car2" class="com.study.SpringDemo5.Car2">
		<property>标签中name就是属性名称,value是普通的属性的值,ref:引用其它对象
		<property name="name" value="丰田"></property>
		<property name="price" value="180000"></property>
	</bean> -->

p名称空间的使用:

为了简化XML文件配置,Spring从2.5开始引入一个新的p名称空间

p:<属性名>="xxx" 引入常量值

p:<属性名>-ref="xxx" 引用其它Bean对象

实例图片:

 SpEl注入:

SpEL:spring expression language ,spring表达式语言,对依赖注入进行简化。

语法:#{表达式}       例子:    <bean id="" value="#{表达式}">

SpEL如何使用呢?(使用方式)

 #{'神回复:哈哈'}使用字符串         

#{topicId3} 使用另一个bean       

 #{topicId4.content.toUpperCase()} 使用指定名属性,并使用方法         

#{T(java.lang.Math).PI} 使用静态字段或方法

实例6:上述方式的实例,代码如下:

创建两个类,Person类,PersonInfo类,代码如下:

package com.study.SpringDemo5;
public class Person {
	private String name;
	private Car2 car2;
	public void setName(String name) {
		this.name = name;
	}
	public void setCar2(Car2 car2) {
		this.car2 = car2;
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", car2=" + car2 + "]";
	}	
}

package com.study.SpringDemo5;
public class PersonInfo {
private String name;

public void setName(String name) {
	this.name = name;
}
public String getName() {
	return name;
}
public String showName() {
	return name;
}
}

接下来编写applicationContext.xml代码,代码如下所示:

<!-- SpEL表达式 -->
	<!-- <bean id="person" class="com.study.SpringDemo5.Person">
		<property name="name" value="#{personInfo.name}"></property>
		<property name="name" value="#{personInfo.showName()}"></property>
		<property name="car2" value="#{car2}"></property>
	</bean>
	
	<bean id="personInfo" class="com.study.SpringDemo5.PersonInfo">
		<property name="name" value="王五"></property>
	</bean> -->

集合属性的注入:

实例7:创建一个类CollectionBean,在类中编写set集合、list集合、map集合等属性,代码如下:

package com.study.SpringDemo6;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public class CollectionBean {
private List<String> list;
private Set<String> set;
private Map<String,String>map;
private Properties properties;
public void setList(List<String> list) {
	this.list = list;
}
public void setSet(Set<String> set) {
	this.set = set;
}
public void setMap(Map<String, String> map) {
	this.map = map;
}
public void setProperties(Properties properties) {
	this.properties = properties;
}
@Override
public String toString() {
	return "CollectionBean [list=" + list + ", set=" + set + ", map=" + map + ", properties=" + properties + "]";
}
}

接下来就是编写applicationContext.xml代码,代码如下:

<!-- demo6集合属性注入 -->
	<bean id="collectionBean" class="com.study.SpringDemo6.CollectionBean">
		<!-- 注入list集合 -->
		<property name="list">
			<list>
				<value>苹果</value>
				<value>香蕉</value>
			</list>
		</property>
		<!-- 注入set集合 -->
		<property name="set">
			<set>
				<value>百度</value>
				<value>头条</value>
			</set>
		</property>
		<!-- 注入map集合 -->
		<property name="map">
			<map>
				<entry key="红色" value="苹果"></entry>
				<entry key="蓝色" value="蓝莓"></entry>
			</map>
		</property>
		<!-- 注入properties -->
		<property name="properties">
			<props>
				<prop key="username">账号</prop>
				<prop key="password">密码</prop>
			</props>
		</property>
	</bean>

最后编写测试类,测试这个实例的代码:

package com.study.SpringDemo6;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.study.SpringDemo5.Car;
public class SpringTest6 {
	@Test
	public void demo1() {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
		CollectionBean collectionBean = (CollectionBean) applicationContext.getBean("collectionBean");
		System.out.println(collectionBean);
	}
}

 加载配置文件的方法:

第一种写法:

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml","applicationContext2.xml",);

第二种写法:

在applicationContext.xml中加入applicationContext.xml文件

<import resource="applicationContext2.xml"/>

spring开发的时候需要的文件:(包含jar包以及applicatonContext.xml配置文件,还有log4j.properties)如下图所示

  

参考:传智播客 www.itcast.com 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值