控制反转降低了类和类之间的耦合度,利于修改和扩展,提供了完整的IOC实现,让我们专注于业务类和Dao类的设计,体现的是面向接口编程的思想,核心是BeanFactory。
需要引入的架包:
commons-logging: spring运行依赖这个组件;
此外还要spring-beans;spring-context;spring-core;spring-expression组件。
本例定个三个接口;Print(打印机),Paper(纸张),Ink(墨盒)
例如:打印机用彩色墨盒在A4纸上打印。
一、初始简单控制反转
1. 创建纸张接口和实现类
public interface Paper {
public String getSize();
}
public class A4Paper implements Paper{
private String size="A4";
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
}
2. 创建配置文件applicationContext.xml
新增resource路径,用来放配置文件;
applicationContext.xml如下:
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 1.IoC控制反转
创建对象,通过bean元素声明需要Spring实例,即对象,id为实例指定名称,class指明了对象的类型 -->
<bean id="A4" class="com.A4Paper"></bean>
</beans>
3. 测试
public class Test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Paper paper = (Paper)ac.getBean("A4");
System.out.println(paper.getSize());
}
}
输出: A4。
不用再像以前一样通过new A4Paper()来创建对象,都交给了容器实现,实现了解耦。
二、注入值
以上的A4Paper的值是实现了中设置的,现在通过spring 的DI(依赖注入)来设置值。
1. 增加Ink接口和实现类
public interface Ink {
public String getColor();
}
public class ColorsInk implements Ink{
private String color;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
不设置具体的值,再配置文件中注入。
2.. 增加print类
public class Print {
private Paper paper;
private Ink ink;
public Paper getPaper() {
return paper;
}
public void setPaper(Paper paper) {
this.paper = paper;
}
public Ink getInk() {
return ink;
}
public void setInk(Ink ink) {
this.ink = ink;
}
/**
*
*/
public Print() {
super();
}
/**
* @param paper
* @param ink
*/
public Print(Paper paper, Ink ink) {
super();
this.paper = paper;
this.ink = ink;
}
public void print(){
System.out.println("使用"+ink.getColor()+"墨盒,在"+paper.getSize()+"纸上打印");
}
}
两个接口参数,不关注具体的实现,只关注接口的使用。
3. applicationContext.xml增加配置如下:
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 1.IoC控制反转
创建对象,通过bean元素声明需要Spring实例,即对象,id为实例指定名称,class指明了对象的类型 -->
<bean id="A4" class="com.A4Paper"></bean>
<bean id="color" class="com.ColorsInk">
<property name="color" value="红色"></property>
</bean>
<bean id="print" class="com.Print">
<!-- 2.DI依赖注入,面向接口编程 setter注入,可以把ref作为标签写在外边,必须有无参构造,在对象创建后赋值
把一个实例注入到另一个实例的属性,用ref注入,name指定set后的属性,在本容器中完成的-->
<property name="ink" ref="color"/>
<property name="paper">
<ref bean="A4"></ref>
</property>
</bean>
</beans>
4. 测试
public class Test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Print print = (Print)ac.getBean("print");
print.print();
}
}
结果: 使用红色墨盒,在A4纸上打印。
三、几种依赖注入方式
<!--1. setter注入,可以把ref作为标签写在外边,必须有无参构造,在对象创建后赋值
把一个实例注入到另一个实例的属性,用ref注入,name指定set后的属性,在本容器中完成的-->
<bean id="print" class="cn.bdqn.springIoC.Print">
<property name="ink" ref="gray"/>
<property name="paper">
<ref bean="A4"></ref>
</property>
</bean>
<!-- 构造注入 ,必须有有参的构造方法,-->
<bean id="print1" class="cn.bdqn.springIoC.Print">
<constructor-arg index="0">
<ref bean="A5"></ref>
</constructor-arg>
<constructor-arg index="1">
<!-- 引用的类有id -->
<ref bean="color"></ref>
<!-- 没有创建id,用bean标签直接引用类 -->
<!-- <bean class="cn.bdqn.springIoC.ColorsInk"></bean> -->
</constructor-arg>
</bean>
<bean id="greet" class="cn.bdqn.springIoC.Greeting">
<!-- 3.setter注入值,给实例的属性赋值,必须有set方法,value是具体的值,name指定set后的属性 -->
<property name="person">
<value>嘎子</value>
</property>
<property name="words">
<value>三天不打小鬼子,手都痒痒。--setter注入值,</value>
</property>
</bean>
<!-- 4.constructor-arg构造注入值,构造器 ,必须有构造方法,可以把value当作属性写里边,也可以放在外边当作标签-->
<bean id="rod" class="cn.bdqn.springIoC.Greeting">
<constructor-arg index="0">
<value>Rod</value>
</constructor-arg>
<constructor-arg index="1">
<value>世界上有两种人,认识二进制的和不认识二进制的。--使用constructor-arg构造注入值</value>
</constructor-arg>
<!-- <property name="person">
<value>Rod</value>
</property>
<property name="words">
<value>世界上有两种人,认识二进制的和不认识二进制的。</value>
</property>
-->
</bean>
<!-- 5.p命名空间实现属性注入 ,先加p的声明,在bean内部设置 p:属性名=”属性值“,用到的比较少,解析易出错-->
<bean id="Tom" class="cn.bdqn.springIoC.Greeting" p:person="Tom" p:words="张嘎是个黑胖子--p命名空间内部设置">
<!-- <property name="person" value="Tom"/>
<property name="words" value="张嘎是个黑胖子"/> -->
</bean>
<!-- 6.注入不同类型的数据,有特殊字符的 -->
<bean id="朱文俊" class="cn.bdqn.springIoC.Greeting">
<property name="person" value="朱文俊">
</property>
<property name="words">
<!-- <value>a>b</value>-->
<value>a<b 采用预定义实体</value>
</property>
</bean>
<!-- 7.集合注入 -->
<bean id="list" class="cn.bdqn.springIoC.Student1">
<property name="person" value="老师">
</property>
<property name="words" value="这是集合的设置值"></property>
<!-- 集合和数组,用list -->
<property name="list">
<list>
<value>List1</value>
<value>List2</value>
<value>List3</value>
</list>
</property>
<!-- set集合,用set -->
<property name="set">
<set>
<value>List1:两个一样的list2,只会显示一个</value>
<value>List2</value>
<value>List2</value>
</set>
</property>
<!-- map集合用下边的标签 -->
<property name="map">
<map>
<entry>
<!-- key的value必须放在外边 -->
<key ><value>键一</value></key>
<value>第一对</value>
</entry>
<entry>
<key ><value>键二</value></key>
<value>第二对</value>
</entry>
</map>
</property>
<!-- Properties类集合,用props标签 -->
<property name="property">
<!-- 输出null -->
<!-- <null/> -->
<!-- 空的“”,{} -->
<value></value>
<!-- <props>
<prop key="prop1">键所对应的值1</prop>
<prop key="prop2">键所对应的值2</prop>
<prop key="prop3">键所对应的值3</prop>
</props>
-->
</property>
</bean>
</beans>