Spring的基礎知識——IOC與DI

一、IOC

        (1)、概念:把對象的建立、初始化、銷燬等工做交給Spring來作java

        (2)、Hello Worldspring

            首先導入必須的jar包數據庫

            

            接着建立bean容器配置文件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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<!-- hello world -->
	<bean id="helloworld" class="ff.helloworld.HelloWorld"></bean>
	
</beans>

            <beans>元素中屬性是一些必要的約束,<bean>元素描述某個類,id屬性是bean惟一標識,class屬性是類的全限定名安全

            而後建立HelloWorld類和測試類,進行測試session

public class HelloWorld {
	
	public void say() {
		System.out.println("Hello World -Spring");
	}

}

       

public class TestHelloWorld {
	
	private ApplicationContext applicationContext;
	
	@Before
	/**
	 * 加載context
	 */
	public void init() {
		
		applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
	}
	
	@Test
	public void testSay() {
		
		HelloWorld hw = (HelloWorld) applicationContext.getBean("helloworld");
		hw.say();
	}
}

            加載配置文件applicationContext.xml生成ApplicationContext對象,再用它的getBean()方法從bean容器中獲取helloworld對象,調用say()方法。
app

    (3)、Spring建立對象的三種方式
框架

        a、構造器(用的最多)
dom

            經過類的構造器建立對象,上面helloworld案例就是經過構造器建立
性能

        b、靜態工廠

           applicationContext.xml中不配置具體的某個bean,而是配置一個工廠bean,在建立工廠bean的時候調用工廠方法(factory-method)建立具體bean。

<!-- 靜態工廠建立bean -->
	<bean 
		id="beanDemoFactory_static" class="ff.beanCreate.BeanDemoFactory_Static" 
		factory-method="getInstance" lazy-init="true"></bean>
public class BeanDemo {
	
	public BeanDemo() {
		System.out.println("i am BeanDemo");
	}
	
	public void say() {
		System.out.println("i am created!");
	}
}
public class BeanDemoFactory_Static {
	
	public static BeanDemo getInstance() {
		
		return new BeanDemo();
	}
}

         c、實例工廠

            application中不配置具體某個bean,而是配置一個工廠bean同時配置一個第三方bean,在建立第三方bean的時候經過factory-bean屬性找到工廠bean,再調用工廠方法(factory-method屬性)建立具體bean。

<!-- 實例工廠建立bean -->
	<bean 
		id="beanDemoFactory_instance" class="ff.beanCreate.BeanDemoFactory_instance"></bean>
	<!-- 第三方bean -->
	<bean 
		id="beanDemo_instance" factory-bean="beanDemoFactory_instance" 
		factory-method="getInstance"></bean>
public class BeanDemo {
	
	public BeanDemo() {
		System.out.println("i am BeanDemo");
	}
	
	public void say() {
		System.out.println("i am created!");
	}
}
public class BeanDemoFactory_instance {
	
	public BeanDemo getInstance() {
		
		return new BeanDemo();
	}
}

          d、爲何要用工廠方式建立對象?

            實現bean建立和使用分離,將bean建立的工做交由工廠來完成。這樣能夠統一管理bean的建立,如能夠在各個bean建立前作一些初始化工做。此外,便於集成其它框架的bean建立管理方法。

    (4)、Spring建立對象的時機

        Spring默認在啓動IoC容器時自動建立對象,但能夠經過配置<bean>元素的lazy-init屬性自定義建立時機。

        lazy-init屬性有三種值:default、false、true。默認值爲default,效果等同於值false,在啓動時建立對象,若將其設置爲true則在獲取bean的時候建立對象。

        注意:通常不設置爲true,緣由是這樣設置後Spring在啓動不會建立這個bean,若是這個bean有bug,那麼啓動時不會報錯,致使存在安全隱患。若一個bean的屬性中含有大量數據,過早的放入內存會影響程序性能,這時候將lazy-init設置爲ture。

    (5)、bean的scope(做用域)

       a、 默認狀況

            默認狀況下Spring建立的bean是單例的,每次獲取bean的時候返回同一個對象,這個bean的屬性天然也被多處引用中共享,這樣很不安全。因此默認狀況下不能將數據定義到bean屬性中。

        b、修改bean的scope

            <bean>元素中的scope屬性能夠修改scope。scope屬性有四個值singleton(單例)、prototype(多例)、request、session,其中prototype爲原型模式,每次獲取bean返回不一樣對象。

        c、選擇單例仍是多例?

            Spring IoC容器在啓動時會建立applicationContext.xml文件中配置的全部bean,實際開發中大多數的bean只會使用到1次,因此默認配置爲單例,對特殊bean配置成多例。

    (6)、scope與建立時機的結合

        a、當scope爲property時,無論lazy-init值是什麼,都在獲取bean的時候建立對象。由於property是多例模式,每次獲取bean的時候都會返回不一樣的對象。

        b、當scope爲singleton時,在何時建立對象由lazy-init決定,且都以單例模式建立。

    (7)、bean初始化,銷燬

        <bean>元素的init-method和destory-method定義初始化和銷燬方法。

    (8)、bean建立、初始化、銷燬的順序

        當Spring啓動(或代碼中獲取bean)時建立bean對象,接着Spring內部調用初始化方法(若是配置),當Spring容器關閉時執行這個bean對象的銷燬方法。

        說明:一、初始化和銷燬方法由Spring內部執行。 二、銷燬方法在Spring容器關閉時執行,但Spring容器通常不會關閉,因此容器裏的對象會一直存在。三、若是<bean>元素的scope屬性值爲property,Spring容器不負責銷燬。

二、 DI(依賴注入)

        (1)、概念:給bean對象屬性賦值

        (2)、三種賦值方式

            a、經過setter方法賦值

                配置<bean>元素內<property>子元素,在bean被建立時調用對應的setter方法給屬性注入值。

<bean id="persion" class="domain.Persion">
		<property name="student" ref="student"></property>
		<property name="string" value="this is a string"></property>
		<property name="list">
			<list>
				<value>index1</value>
				<value>index2</value>
				<ref bean="student"/>
			</list>s
		</property>
	</bean>
public class Persion {
	
	private Student student;  // Student對象
	private String string;
	private List list;
	
	public void say(Student student) {
		student.say();
	}

	public void setStudent(Student student) {
		this.student = student;
	}

	public void setString(String string) {
		this.string = string;
	}

	public void setList(List list) {
		this.list = list;
	}
}

        當Person對象被建立時,Spring經過<property>元素找到對應的setter方法,將配置的值注入。

        <property>元素給屬性注入值,value爲基本類型以及String類型值,ref爲引用屬性的bean的id,array、list、map爲集合屬性

            b、經過構造方法賦值

                在<bean>元素內配置<constructor-arg>元素,當Persion類被建立時調用對應的構造器爲屬性賦值。

<bean id="student" class="ff.ing.pojo.Student">
		<constructor-arg index="0" value="蓋倫"></constructor-arg>
	</bean>
	
	<bean id="persion" class="ff.ing.pojo.Persion">
		<constructor-arg index="0" value="007"></constructor-arg>
		<constructor-arg index="1" value="趙信"></constructor-arg>
		<constructor-arg index="2" ref="student"></constructor-arg>
	</bean>
public class Persion {
	
	private int id;
	private String name;
	private Student student;
	
	public Persion() {
		
	}
	
	public Persion(int id, String name, Student student) {
		
		this.id = id;
		this.name = name;
		this.student = student;
	}
	
	public void say() {
		String str = "id:" + id + "   name:" + name + "   student:" + student.getName();
		System.out.println(str);
	}
}

       index屬性爲構造器參數列表中參數的序號。    

        c、經過註解賦值

            一、依賴注入註解

          (1) 首先須要修改applicationContext.xml文件:添加註解命名空間約束,啓動依賴注入註解解析器

<!-- 添加註解命名空間約束 -->
xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
		
<!-- 啓動依賴注入註解解析器 -->
<context:annotation-config/>

<!-- bean -->
<bean>........</bean>

        (2) 在類中使用註解

public class Persion {
	
	private int id;
	private String name;
	
	@Resource(name="student")
	private Student student;
	
    ………
    ………
}

   @Resource會到IoC容器中尋找id與name匹配的bean,賦值給student屬性。

    @Resource是java內置註解,Spring框架定義了本身的註解。@Autowired按照類型進行匹配;@Qualifier(value="xxx")按照id進行匹配,且只能與@Autowired組合使用,沒法單獨使用。

    註解只能注入引用類型值,沒法注入基本類型、String類型以及集合類型值

    註解方式比xml配置方式效率低。   

    二、類掃描註解

    (1)、首先須要修改applicationContext.xml文件:添加註解命名空間約束,啓動類掃描註解解析器,配置要掃描的包

<!-- 添加註解命名空間約束 -->
xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

<!-- 啓動類掃描註解解析器,配置要掃描的包 -->
<context:component-scan base-package="ff.ing.pojo"></context:component-scan>

    (2)在類中使用註解

@Component(value="student")
public class Student {
	
	private String name;
	
	public Student() {
		
	}
	……
	……
}


@Component(value="persion")
public class Persion {
	
	private int id;
	private String name;
	
	@Resource(name="student")
	private Student student;
	
	public Persion() {
		
	}
	……
	……
}

    @Component配置了這個類的在spring容器中的id,以Persion類爲例@Component(value="persion")至關於<bean id="persion" class="……"></bean>

    Spring還提供了更細分的組件註解:@Repository@Service@Controller,分別表明dao層、業務層和控制層。他們的用法以及功能與@Component一致,只是方便了代碼的閱讀而已。

    類掃描註解方式比依賴注入註解方式效率還低。

  ● IoC、DI中的類繼承問題

      當使用setter和構造器方法給屬性輸入值時,子類沒法繼承父類中屬性的值,這時須要在<bean>元素中添加parent屬性。使用註解不存在這樣的問題

  ● IoC與DI的意義

    ● IoC與DI最生動的解釋(摘抄他人)

首先想說說IoC(Inversion of Control,控制倒轉)。這是spring的核心,貫穿始終。所謂IoC,對於spring框架來講,就是由spring來負責控制對象的生命週期和對象間的關係。這是什麼意思呢,舉個簡單的例子,咱們是如何找女友的?常見的狀況是,咱們處處去看哪裏有長得漂亮身材又好的mm,而後打聽她們的興趣愛好、號碼………,想辦法認識她們,投其所好送其所要,而後嘿嘿……這個過程是複雜深奧的,咱們必須本身設計和麪對每一個環節。傳統的程序開發也是如此,在一個對象中,若是要使用另外的對象,就必須獲得它(本身new一個,或者從JNDI中查詢一個),使用完以後還要將對象銷燬(好比Connection等),對象始終會和其餘的接口或類藕合起來。

那麼IoC是如何作的呢?有點像經過婚介找女友,在我和女友之間引入了一個第三者:婚姻介紹所。婚介管理了不少男男女女的信息,我能夠向婚介提出一個列表,告訴它我想找個什麼樣的女友,好比長得像李嘉欣,身材像林熙雷,唱歌像周杰倫,速度像卡洛斯,技術像齊達內之類的,而後婚介就會按照咱們的要求,提供一個mm,咱們只須要去和她談戀愛、結婚就好了。簡單明瞭,若是婚介給咱們的人選不符合要求,咱們就會拋出異常。整個過程再也不由我本身控制,而是有婚介這樣一個相似容器的機構來控制。Spring所倡導的開發方式就是如此,全部的類都會在spring容器中登記,告訴spring你是個什麼東西,你須要什麼東西,而後spring會在系統運行到適當的時候,把你要的東西主動給你,同時也把你交給其餘須要你的東西。全部的類的建立、銷燬都由 spring來控制,也就是說控制對象生存週期的再也不是引用它的對象,而是spring。對於某個具體的對象而言,之前是它控制其餘對象,如今是全部對象都被spring控制,因此這叫控制反轉。若是你還不明白的話,我決定放棄。

IoC的一個重點是在系統運行中,動態的向某個對象提供它所須要的其餘對象。這一點是經過DI(Dependency Injection,依賴注入)來實現的。好比對象A須要操做數據庫,之前咱們老是要在A中本身編寫代碼來得到一個Connection對象,有了 spring咱們就只須要告訴spring,A中須要一個Connection,至於這個Connection怎麼構造,什麼時候構造,A不須要知道。在系統運行時,spring會在適當的時候製造一個Connection,而後像打針同樣,注射到A當中,這樣就完成了對各個對象之間關係的控制。A須要依賴 Connection才能正常運行,而這個Connection是由spring注入到A中的,依賴注入的名字就這麼來的。那麼DI是如何實現的呢? Java 1.3以後一個重要特徵是反射(reflection),它容許程序在運行的時候動態的生成對象、執行對象的方法、改變對象的屬性,spring就是經過反射來實現注入的。

    ● 意義

        實現了徹底面向接口編程(程序設計依賴於抽象的接口而非具體實現類),在代碼中不須要關心具體是哪一個實現類在工做。

相關文章
相關標籤/搜索