天天看点

spring(一)控制反转和依赖注入

       控制反转降低了类和类之间的耦合度,利于修改和扩展,提供了完整的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&lt;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>