引言
上一篇文章中,我们接上了如何使用idea创建第一个Spring,在文中,Person和Axe含有依赖关系!那么Spring如何管理它们之间的关系呢!!
Spring核心功能
- Spring 容器作为超级大工厂, 负责创建、管理所有的Java 对象,这些Java 对象被称为Bean。
- Spring 容器管理容器中Bean 之间的依赖关系,Spring使用一种被称为“依赖注入”的方式来管理Bean 之间的依赖关系。
Spring本质
Spring的本质:通过XML配置来驱动Java代码。Spring用的熟:几乎所有Java代码都放在XML去配置。要求:眼中看到的XML配置,心中想的是执行的Java代码。
bean元素 :驱动使用new调用构造器。 默认它总是调用无参数的构造器。如果想控制它调用有参数的构造器,就需要在<bean…/>元素里添加
<constructor-arg…/>子元素,每个该元素代表一个构造器参数。
<constructor-arg…/>子元素里value属性指定的值优先被当成String类处理。为了明确地指定该值的类型,可以指定type属性。
property元素: 驱动它调用setter方法。 对象创建出来之后,立即就会被调用。
constructor-arg元素: 驱动调用有参数的构造器。
依赖注入
IOC与依赖注入
两者是同一行为的两种表达,只是描述角度不同!IOC是从调用者的角度出发,调用者不用再主动·获取依赖对象,而是由Spring容器自动为其赋值,因此调用者由原来的主动获取依赖对象变成了被动接受。而依赖注入是从Spring容器的角度来看,Spring容器负责将依赖对象赋值给调用者的成员变量。
实现方式’
依赖注入可分为3种:
- 接口注入。很少使用。
- 设值注入:就是通过property元素控制调用setter方法,就是所谓的设值注入。
- 构造注入:就是constructor-arg控制调用有参数的构造器,由构造器来注入被依赖组件。
设值注入
public interface Person {
//定义一个使用斧头的方法
public void useAxe();
}
public interface Axe {
//Axe接口中定义一个chop()方法
public String chop();
}
public class Chinese implements Person {
private Axe axe;
public void setAxe(Axe axe ){
this.axe=axe;
}
@Override
public void useAxe(){
System.out.println(axe.chop());
}
}
public class StoneAxe implements Axe{
@Override
public String chop(){
return "石斧砍柴好慢";
}
}
<?xml version="1.0" encoding="GBK"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<!-- 配置名为person的Bean,其实现类是org.crazyit.app.service.Person类 -->
<bean id="chinese" class="Chinese">
<!-- 控制调用setAxe()方法,将容器中axe Bean作为传入参数 -->
<property name="axe" ref="stoneAxe"/>
</bean>
<!-- 配置名为axe的Bean,其实现类是org.crazyit.app.service.Axe类 -->
<bean id="stoneAxe" class="StoneAxe"/>
<!-- 配置名为win的Bean,其实现类是javax.swing.JFrame类 -->
<bean id="win" class="javax.swing.JFrame"/>
<!-- 配置名为date的Bean,其实现类是java.util.Date类 -->
<bean id="date" class="java.util.Date"/>
</beans>
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanTest {
public static void main(String[] args)throws Exception
{
// 创建Spring容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config.xml");
// 获取id为person的Bean
Person p = ctx.getBean("chinese" , Person.class);
// 调用useAxe()方法
p.useAxe();
}
}
使用Spring IoC 容器的三个基本要点
- 应用程序的各组件面向接口编程。面向接口编程可以将组件之间的精合关系提升到接口层次,从而有利于项目后期的扩展。
- 应用程序的各组件不再由程序主动创建,而是由Spring容器来负责产生并初始化。
- Spring采用配置文件或注解来管理Bean的实现类,依赖关系,Spring 容器则根据配置文件或注解,利用反射来创建实例,并为之注入依赖关系。
构造注入
public class Chinese implements Person {
private Axe axe;
public Chinese(Axe axe){
this.axe=axe;
}
@Override
public void useAxe(){
System.out.println(axe.chop());
}
}
<?xml version="1.0" encoding="GBK"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<!-- 配置名为person的Bean,其实现类是org.crazyit.app.service.Person类 -->
<bean id="chinese" class="Chinese">
<constructor-arg ref="stoneAxe"/>
</bean>
<!-- 配置名为axe的Bean,其实现类是org.crazyit.app.service.Axe类 -->
<bean id="stoneAxe" class="StoneAxe"/>
<!-- 配置名为win的Bean,其实现类是javax.swing.JFrame类 -->
<bean id="win" class="javax.swing.JFrame"/>
<!-- 配置名为date的Bean,其实现类是java.util.Date类 -->
<bean id="date" class="java.util.Date"/>
</beans>
二者区别
区别在于:创建Person 实例中Axe属性的时机不同一一设值注入是先通过无参数的构造器创建一个Bean 实例,然后调用对应的setter 方法注入依赖关系: 而构造注入则直接调用有参数的构造器,当Bean 实例创建完成后,己经完成了依赖关系的注入。