spring是使用的di實現了ioc的功能, spring底層建立對象,使用的是反射機制。java
spring是一個容器,管理對象,給屬性賦值, 底層是反射建立對象spring
bean 實例在調用無參構造器建立對象後,就要對 bean 對象的屬性進行初始化。app
初始化是由容器自動完成的,稱爲注入
根據注入方式的不一樣,經常使用的有兩類:set 注入、構造注入ide
set 注入也叫設值注入,是指經過 setter 方法傳入被調用者的實例,這種注入方式簡單、直觀,於是在 Spring 的依賴注入中大量使用測試
項目的具體建立看上一篇就能夠了,這裏直接寫重點this
首先聲明一個Studnet的類spa
package com.md.b1; /** * @author MD * @create 2020-08-07 19:55 */ public class Student { private String name; private int age; public Student() { System.out.println("我是Student類的無參構造方法"); } public void setName(String name) { System.out.println("setName:"+name); this.name = name; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
而後寫對應的配置文件code
<?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"> <!-- 聲明Student的對象 簡單類型:spring中java的基本數據類型和String都是簡單數據類型 di:給屬性賦值也就是注入 1. set注入 :spring來調用類的set方法,在set方法中完成屬性的賦值 1. 簡單類型的注入 <bean id="xx" class="yyy"> <property name="屬性名字" value="此屬性的值"/> 一個property只能給一個屬性賦值 <property....> </bean> 必需要有屬性對應的set方法,沒有的話就報錯 可是set方法裏面的內容是你能控制,除了賦值,你還能夠在set裏多寫幾條java語句 --> <bean id="student" class="com.md.b1.Student"> <property name="name" value="張三" /> <!-- setName("張三")--> <property name="age" value="20"/> </bean> </beans>
結構圖xml
測試類對象
注意:此時因爲這個文件不是直接在resources下面,而是在下面的b1包的下面,因此指定的路徑得加上
@Test public void test01(){ String config = "b1/applicationContext.xml"; ApplicationContext ac = new ClassPathXmlApplicationContext(config); // 從容器中獲取Student的對象 Student student = (Student) ac.getBean("student"); System.out.println(student); // 我是Student類的無參構造方法 // setName:張三 // Student{name='張三', age=20} }
注意一:沒有屬性但有set方法
還能夠在Student的類中加入這個方法,
public void setEmail(String eamil) { System.out.println("setEmail:"+eamil); }
對應的配置文件
<bean id="student" class="com.md.b1.Student"> <property name="name" value="張三" /> <!-- setName("張三")--> <property name="age" value="20"/> <property name="email" value="zs@qq.com"/> </bean>
此時在Student類中沒有email屬性,可是有setEmail方法,能順利執行不?
能,只要有對應的set方法都是正確的,不管屬性名是否存在
測試:
@Test public void test01(){ // 注意:此時因爲這個文件不是直接在resources下面,而是在下面的b1包的下面,因此指定的路徑得加上 String config = "b1/applicationContext.xml"; ApplicationContext ac = new ClassPathXmlApplicationContext(config); // 從容器中獲取Student的對象 Student student = (Student) ac.getBean("student"); System.out.println(student); // 我是Student類的無參構造方法 // setName:張三 // setEmail:zs@qq.com // Student{name='張三', age=20} }
注意二:對於非自定義的類
在配置文件中
<!-- 非自定義類設置屬性 只有這個類中有setXXX(),就能夠 --> <bean id="mydate" class="java.util.Date"> <!--setTime(993462034956)--> <property name="time" value="9348362034" /> </bean>
測試:
@Test public void test02(){ String config = "b1/applicationContext.xml"; ApplicationContext ac = new ClassPathXmlApplicationContext(config); Date mydate = (Date) ac.getBean("mydate"); System.out.println(mydate); }
當指定 bean 的某屬性值爲另外一 bean 的實例時,經過 ref 指定它們間的引用關係
ref的值必須爲某 bean 的 id 值
以下:
先建立一個School類
package com.md.b2; /** * @author MD * @create 2020-08-07 20:40 */ public class School { private String name; private String address; public void setName(String name) { this.name = name; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "School{" + "name='" + name + '\'' + ", address='" + address + '\'' + '}'; } }
再建立一個Student類,在裏面引用School的類的對象
package com.md.b2; /** * @author MD * @create 2020-08-07 19:55 */ public class Student { private String name; private int age; // 聲明一個引用數據類型 private School school; public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } public void setSchool(School school) { System.out.println("setSchool:"+school); this.school = school; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", school=" + school + '}'; } }
寫對應的配置文件
<?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"> <!-- 2. 引用數據類型的注入:spring來調用類的set方法, <property name="屬性名稱" ref="bean的id也就是對象的名稱"/> --> <!-- 聲明school對象 --> <bean id="school" class="com.md.b2.School"> <property name="name" value="清華"/> <property name="address" value="北京"/> </bean> <bean id="student" class="com.md.b2.Student"> <property name="name" value="張三"/> <property name="age" value="40"/> <!-- 引用數據類型,調用的是setSchool(school),就是上面的 --> <property name="school" ref="school"/> </bean> </beans>
測試:
@Test public void test02(){ // 注意:此時因爲這個文件不是直接在resources下面,而是在下面的b2包的下面,因此指定的路徑得加上 String config = "b2/applicationContext.xml"; ApplicationContext ac = new ClassPathXmlApplicationContext(config); Student student = (Student) ac.getBean("student"); System.out.println(student); // setSchool:School{name='清華', address='北京'} // Student{name='張三', age=40, school=School{name='清華', address='北京'}} }
構造注入是指,spring在調用類的有參構造方法,在建立對象的同時,在構造方法中進行屬性的賦值
語法:使用<constructor-arg />標籤,具體看下面的使用
首先還在Student類中寫有參構造器
public Student(String name, int age, School school) { System.out.println("我是Student類的有參構造方法"); this.name = name; this.age = age; this.school = school; }
而後在配置文件中
<?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"> <!-- 構造注入 spring在調用類的有參構造方法,在建立對象的同時,在構造方法中進行屬性的賦值 構造注入使用 <constructor-arg> 標籤 <constructor-arg> 標籤:一個<constructor-arg>表示構造方法一個參數。 <constructor-arg> 標籤屬性: name:表示構造方法的形參名 index:表示構造方法的參數的位置,參數從左往右位置是 0 , 1 ,2的順序 value:構造方法的形參類型是簡單類型的,使用value ref:構造方法的形參類型是引用類型的,使用ref --> <!-- 聲明school對象 --> <bean id="school" class="com.md.b3.School"> <property name="name" value="清華"/> <property name="address" value="北京"/> </bean> <!--推薦用name--> <!--調用類的有參構造方法--> <!--<bean id="student" class="com.md.b3.Student">--> <!--<constructor-arg name="name" value="張三"/>--> <!--<constructor-arg name="age" value="30"/>--> <!--<constructor-arg name="school" ref="school"/>--> <!--</bean>--> <!-- 或者這樣也是能夠的,根據參數的位置--> <!--<bean id="student" class="com.md.b3.Student">--> <!--<constructor-arg index="0" value="張三"/>--> <!--<constructor-arg index="1" value="30"/>--> <!--<constructor-arg index="2" ref="school"/>--> <!--</bean>--> <!----> <!--或者直接省略--> <bean id="student" class="com.md.b3.Student"> <constructor-arg value="張三"/> <constructor-arg value="30"/> <constructor-arg ref="school"/> </bean> </beans>
測試:
@Test public void test01(){ // 注意:此時因爲這個文件不是直接在resources下面,而是在下面的b3包的下面,因此指定的路徑得加上 String config = "b3/applicationContext.xml"; ApplicationContext ac = new ClassPathXmlApplicationContext(config); Student student = (Student) ac.getBean("student"); System.out.println(student); // 我是Student類的有參構造方法 // Student{name='張三', age=30, school=School{name='清華', address='北京'}} }
對於引用類型屬性的注入,也可不在配置文件中顯示的注入。能夠經過爲<bean/>標籤設置 autowire 屬性值,爲引用類型屬性進行隱式自動注入(默認是不自動注入引用類型屬性)
根據自動注入判斷標準的不一樣,能夠分爲兩種:
當配置文件中被調用者 bean 的 id 值與代碼中調用者 bean 類的屬性名相同時,可以使用byName 方式,讓容器自動將被調用者 bean 注入給調用者 bean。容器是經過調用者的 bean類的屬性名與配置文件的被調用者 bean 的 id 進行比較而實現自動注入的
語法:
byName(按名稱注入) : java類中引用類型的屬性名和spring容器中(配置文件)<bean>的id名稱同樣, 且數據類型是一致的,這樣的容器中的bean,spring可以賦值給引用類型。 語法: <bean id="xx" class="yyy" autowire="byName"> 簡單類型屬性賦值 </bean>
例子:
public class School { private String name; private String address; // 省略set } //--------------------------------- public class Student { private String name; private int age; // 聲明一個引用數據類型 private School school; // 省略set }
在配置文件中
<bean id="school" class="com.md.b4.School"> <property name="name" value="北大"/> <property name="address" value="北京"/> </bean> <!--/////////////////////////////--> <bean id="student" class="com.md.b4.Student" autowire="byName"> <property name="name" value="張三"/> <property name="age" value="20"/> <!--自動賦值引用數據類型--> </bean>
如上:
java類中引用類型的屬性名school 和 spring容器中(配置文件)<bean>的id名稱同樣,且數據類型一致,這樣就能自動注入
使用 byType 方式自動注入,要求:配置文件中被調用者 bean 的 class 屬性指定的類,要與代碼中調用者 bean 類的某引用類型屬性類型同源。即要麼相同,要麼有 is-a 關係(子類,或是實現類)
但這樣的同源的被調用 bean 只能有一個。多於一個,容器就不知該匹配哪個了
語法:
byType(按類型注入) : java類中引用類型的數據類型和spring容器中(配置文件)<bean>的class屬性 是同源關係的,這樣的bean可以賦值給引用類型 同源就是一類的意思: 1.java類中引用類型的數據類型和bean的class的值是同樣的。 2.java類中引用類型的數據類型和bean的class的值父子類關係的。 3.java類中引用類型的數據類型和bean的class的值接口和實現類關係的 語法: <bean id="xx" class="yyy" autowire="byType"> 簡單類型屬性賦值 </bean> 注意:在byType中, 在xml配置文件中聲明bean只能有一個符合條件的, 多餘一個是錯誤的
仍是上面的例子:
在實際應用裏,隨着應用規模的增長,系統中 Bean 數量也大量增長,致使配置文件變得很是龐大、臃腫。爲了不這種狀況的產生,提升配置文件的可讀性與可維護性,能夠將Spring 配置文件分解成多個配置文件,其中一個爲主配置文件
total.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"> <!-- 包含關係的配置文件: total表示主配置文件 : 包含其餘的配置文件的,主配置文件通常是不定義對象的。 語法:<import resource="其餘配置文件的路徑" /> 關鍵字:"classpath:" 表示類路徑(class文件所在的目錄), 在spring的配置文件中要指定其餘文件的位置, 須要使用classpath,告訴spring到哪去加載讀取文件。 --> <!--加載的是文件列表--> <!-- <import resource="classpath:b4/spring-school.xml" /> <import resource="classpath:b4/spring-student.xml" /> --> <!--/////////////////////////////--> <!-- 在包含關係的配置文件中,能夠通配符(*:表示任意字符) 注意: 主的配置文件名稱不能包含在通配符的範圍內(不能叫作spring-total.xml) --> <import resource="classpath:b4/spring-*.xml" /> </beans>
spring調用類的set方法實現屬性賦值
<property name="屬性名" value="屬性的值"/>
<property name="屬性名" ref="bean的id"/>
spring調用有參數的構造方法
<constructor-arg>的name屬性,name表示構造方法的形參名
<constructor-arg>的index屬性,表示構造方法形參的位置,從0開始
由spring根據某些規則,給引用類型完成賦值,有byName、byType
java類中引用類型的屬性名和spring容器中bean的id同樣,數據類型同樣
java類中引用類型的數據類型和spring容器中bean的class是同源關係