SSM(一):spring-ioc依賴注入筆記
一、java代理模式
java代理模式是ioc的前置知識。代理模式非常簡單,看程式碼就一目瞭然了。
public interface role { public void makeMoney(); }role
public class Boss implements role { @Override public void makeMoney() { System.out.println("老闆正在談專案..."); } }boss
publicsecretaryclass Secretary implements Role { private Role subject = new Boss(); @Override public void makeMoney() { before(); subject.makeMoney(); after(); } private void before(){ System.out.println("你可以先和祕書談一下合作意向..."); } private voidafter(){ System.out.println("祕書把老闆簽過的合同給你..."); } }
上面是極簡的java靜態代理(也是介面代理模式),定義了介面、介面的實現類和代理類。或者稱實現類為目標類,代理類為封裝類。
一般我們先找老闆的祕書,說一下合作意向(Secretary的makeMoney),可以的話(before)呼叫老闆真正談專案(Boss的makeMoney),談妥了就可以籤合同了(after)。可以做一下測試:
public class Test { publicTeststatic void main(String[] args){ // 測試靜態代理 /* 所謂靜態代理,是對介面實現類的某些方法進行了一次封裝 這個代理類需要實現介面的同樣方法,並在內部初始化一個實現類 在該方法中呼叫了實現類的方法 */ Secretary proxy = new Secretary(); proxy.makeMoney(); } }
可見,與其直接訪問一個目標類,更多的是訪問封裝類。這樣做的好處在於:
1.不操作目標類,不對目標類造成破壞;
2.自定義封裝類,具有充分的控制權;
3.可以增強目標類的特定方法,達到增強和擴充套件的目的;
但是,目標類和封裝類必須實現介面定義的同一個方法。
更多地,java使用動態代理來實現功能擴充套件。舉個例子:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class Test { public static void main(String[] args) { final Role role = new Boss(); Role secretary = (Role) Proxy.newProxyInstance( role.getClass().getClassLoader(), // 目標類的類載入器 role.getClass().getInterfaces(), // 目標類所實現的所有介面 new InvocationHandler() { // 內部匿名類 -- InvocationHandler介面類的實現類,必須重寫介面方法invoke @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // proxy: 代理物件 // method: 目標方法 // args: 目標方法的引數列表 before(); Object result = method.invoke(role, args); after(); return result; } private void before(){ System.out.println("先和祕書接洽約時間..."); } private void after(){ System.out.println("祕書送來合同書..."); } } ); secretary.makeMoney(); } }jdk動態代理
jdk動態代理同樣是介面代理模式,new InvocationHandler()實現類中的invoke方法被Proxy.newProxyInstance自動呼叫。secretary物件相當於上面的secretary物件,只不過不需要我們自己手動建立了。jdk動態代理幫助我們建立了一個代理物件,我們只需寫介面和實現類即可。
當然,上面的new InvocarionHandler()實現類可以單獨拿出來重寫:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class JdkProxy implements InvocationHandler { private Object impl; JdkProxy(Object impl){ super(); this.impl = impl; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before(); Object result = method.invoke(impl, args); after(); return result; } private void before(){ System.out.println("先和祕書接洽約時間..."); } private void after(){ System.out.println("祕書送來合同書..."); } }JdkProxy
做一下測試:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class JdkProxyTest { public static void main(String[] args) { Role role = new Boss(); InvocationHandler invocationHandler = new JdkProxy(role); Role boss = (Role) Proxy.newProxyInstance( role.getClass().getClassLoader(), role.getClass().getInterfaces(), invocationHandler ); boss.makeMoney(); } }test
除了jdk動態代理外,還有cglib動態代理。與jdk動態代理不同的是,cglib動態代理沒有介面類,它是通過子類繼承目標類,在子類同名方法內部呼叫目標類方法來實現的。這種實現方法的效能要優於jdk動態代理。
總結一下,jdk代理幫助我們在目標類的基礎上做了一次功能擴充套件,因此,對於日誌、事務等系統級業務,可以通過動態代理交給別的元件管理,自己則專注寫應用級業務,也就是上面的實現類(對應bean)和Test類(對應service)。這就是IOC控制反轉。
二、applicationContext.xml和ApplicationContext
“解耦(業務邏輯程式碼和實體類分離)”、“功能擴充套件和託管(系統級業務交給框架處理,開發者只專注應用級業務處理)”是理解spring容器的兩個重要思想。
動態代理解決了“功能擴充套件和託管”這個問題,通過xml解析,spring容器(讀取applicationContext.xml生成的ApplicationContext例項)對目標類和封裝類、業務程式碼兩者進行了拆解。
我們可以將目標類注入(DI)到applicationContetx.xml檔案中,由spring容器(ApplicationContext例項)讀取applicationContext.xml來自動生成目標類對應的介面類和封裝類。在業務程式碼中,只需獲取ApplicationContext例項,並從中獲取響應的封裝類即可。這個過程實現即是IOC控制反轉。
假設專案環境(IDEA)已經搭建完成(主要是JDK配置、maven配置、tomcat-->local伺服器配置、專案Open Modules Settings配置、以及maven下檔案新增及屬性配置Mark Directory as)。
D:.
├─src
│ ├─main
│ │ ├─java // Sources Root
│ │ │ └─com
│ │ │ └─boke
│ │ ├─resources // Resources Root,可以手動新增並右鍵設定Mark Directory as --> Resources Root
│ │ │ ├─applicationContext.xml
│ │ │ └─log4j.properties
│ │ └─webapp // Sources Root,可以手動新增並右鍵設定Mark Directory as --> Sources Root
│ │ └─WEB-INF
│ └─test
│ └─java // Test Resources Root,可以手動新增並右鍵設定Mark Directory as --> Test Resources Root
│ └─com
│ └─node
│ ├─boke
└─target // Excluded,自動生成
備註:這些都可以在專案配置中設定。IDEA右上角"搜尋"圖示左側第一個圖示,或者專案檔案目錄上右鍵Open Module Settings設定。
maven專案檔案配置
pom.xml需要引入的依賴:junit4.11、spring-core、spring-beans、spring-context、spring-aop、spring-expression、log4j1.2.17、spring-test、commons-logging1.1.1。springframework版本為4.2.1.RELEASE。
現在跑一遍applicationContext.xml-->ApplicationContext的整個流程。
定義介面類和實現類。
// MyInterface類 public interface MyInterface { public void doSome(); } // MyImplement類 public class MyImplement implements MyInterface { public MyImplement(){ super(); } public void doSome() { System.out.println("--------執行doSome()方法...----------"); } }介面類和實現類
將實現類註冊到applicationContext.xml檔案中。通常,實現類是一個POJO(plain old java object),對應applicationCOntext.xml的某個bean標籤,因此也可稱為bean物件。
<?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"> <!-- 註冊MyImplement 它相當於:MyInterface implement = (MyInterface) new MyImplement(); --> <bean id="implement" class="com.boke.MyImplement" /> </beans>依賴注入
測試。
package com.node.boke; import com.boke.MyInterface; import com.boke.MyImplement; import org.junit.Test; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; import org.springframework.core.io.ClassPathResource; public class MyTest { /** * 示例一:傳統的開發模式:介面-->實現-->呼叫,都繫結在了一起,耦合度比較高 */ @Test public void test01(){ MyInterface implement = new MyImplement(); implement.doSome(); } /** * 示例二:spring容器解耦 */ @Test public void test02(){ /* ClassPathXmlApplicationContext:類路徑 把resources設定為source root,然後直接從其資料夾下讀取applicationContext.xml即可 解耦:看不到MyInterface實現類 */ ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); MyInterface implement = (MyInterface)ac.getBean("implement"); implement.doSome(); } /** * 示例三:檔案路徑 */ @Test public void test03(){ /* FileSystemXmlApplicationContext:檔案路徑,預設是專案根路徑下,也可以從其他路徑讀取applicationContext.xml檔案 解耦:看不到ISomeimplementImpl實現類 */ ApplicationContext ac = new FileSystemXmlApplicationContext("applicationContext.xml"); MyInterface implement = (MyInterface)ac.getBean("implement"); implement.doSome(); } /* applicationContext與BeanFactory的區別: - applicationContext容器在進行初始化時,會將其中的所有Bean(物件)建立; 缺點:佔用系統資源(記憶體,CPU等) 優點:響應速度快 - BeanFactory容器中的物件在容器初始化不會建立Bean物件,而是在真正獲取該物件時才建立; 缺點:響應速度慢 優點:佔用系統資源相對較小 */ /** * 示例四:XmlBeanFactory介面類的實現 */ @SuppressWarnings("deprecation") @Test public void test04(){ BeanFactory ac = new XmlBeanFactory(new ClassPathResource("applicationContext.xml")); MyInterface implement = (MyInterface)ac.getBean("implement"); implement.doSome(); } }測試
總結:
Spring的主要作用就是為程式碼"解耦",降低程式碼間的耦合度。根據功能的不同,可以將一個系統中的程式碼分為主業務邏輯和系統級業務邏輯兩類。主業務程式碼邏輯聯絡緊密,有具體的專業業務應用場景,複用性相對較低;系統級業務邏輯相對功能獨立,沒有具體的專業業務應用場景,為主業務提供系統級服務,複用性強。
Spring根據程式碼的功能特點,將降低耦合度的方式分為兩類:IOC和AOP。IOC使得主業務邏輯在相互呼叫的過程中不用自己建立物件和呼叫,而是由Spring容器統一管理,自動"注入"。AOP使得系統級服務得到了服用,由Spring容器統一完成"織入"。
Spring的特點:
- 1.非入侵:spring的api不會混入到應用業務開發中。
- 2.容器:Spring可以管理物件的生命週期以及物件間的依賴關係,並且可以通過配置檔案來定義物件,以及設定與其它物件的依賴關係。
- 3.IOC: 控制反轉(inversion of control),即建立呼叫者的例項不是由呼叫者完成的,而是由Spring容器完成,並注入呼叫者。
即不是物件從容器中查詢物件,這個事情是容器在物件初始化時不等物件請求就主動將依賴傳遞給它。
- 4.AOP:面向切面程式設計(Aspect Orient Programming),是一種程式設計思想,是面向物件程式設計的OOP的補充。可以把日誌、安全、事務管理等服務理解成一個"切面"。
三、ApplicationContext在bean注入時增擴了哪些功能--bean的生命始末
IOC(Inversion of Control)是一個概念,是一種思想,其實現方式多種多樣。當前比較流行的實現方式有兩種:依賴查詢、依賴注入。依賴查詢(Dependency Lookup DL):容器提供回撥介面和上下文環境給元件,程式程式碼則需要提供具體的查詢方式。 依賴注入(Dependecy Injection DI):程式程式碼不做定位查詢,這些工作由容器自行完成。依賴注入是目前最優秀的解耦方式。依賴注入讓Spring的Bean之間以配置檔案的方式組織在一起,而不是以硬編碼的方式耦合在一起。
通過以下程式碼檢視bean注入和銷燬的整個流程。
// 介面類 package com.boke; public interface MyInterface { public void doSome(); } // 實現類 package com.boke; import org.springframework.beans.BeansException; import org.springframework.beans.factory.*; import org.springframework.beans.factory.config.BeanPostProcessor; public class MyImplement implements MyInterface, BeanNameAware, BeanFactoryAware, InitializingBean, DisposableBean, BeanPostProcessor { private String aDao; private String bDao; public MyImplement(){ System.out.println("Step1.執行構造方法..."); } @Override public void doSome() { System.out.println("Step9:執行真正的業務處理邏輯doSome()方法..."); } public void setUp(){ System.out.println("Step7:bean生命開始..."); } public void tearDown(){ System.out.println("Step11:Bean銷燬之前..."); } public String getaDao() { return aDao; } public void setaDao(String aDao) { System.out.println("Step2:執行aDao的setter方法..."); this.aDao = aDao; } public String getbDao() { return bDao; } public void setbDao(String bDao) { System.out.println("Step2:執行bDao的setter方法..."); this.bDao = bDao; } @Override public void setBeanName(String name) { System.out.println("Step3:獲取bean的id = " + name); } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { System.out.println("Step4:獲取到BeanFactory容器..."); } @Override public void afterPropertiesSet() throws Exception { System.out.println("Step6:標誌著bean已經初始化完畢..."); } @Override public void destroy() throws Exception { System.out.println("Step10:實現介面的銷燬之前..."); } @Override public Object postProcessBeforeInitialization(Object bean, String s) throws BeansException { System.out.println("Step5:初始化完畢之前,執行before方法..."); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String s) throws BeansException { System.out.println("Step8:初始化完畢之後,執行after方法..."); return 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"> <!--測試生命bean--> <bean id="implement" class="com.boke.MyImplement" init-method="setUp" destroy-method="tearDown" > <!--初始化ISomeServiceImpl的成員變數--> <property name="aDao" value="aaa" /> <property name="bDao" value="bbb" /> </bean> </beans>applicationContext.xml
測試類。
package com.node.boke; import com.boke.MyInterface; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { @Test public void test01(){ ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); MyInterface service = (MyInterface)ac.getBean("implement"); service.doSome(); /* 要執行tearDown,需要兩個條件: - scope=singleton - 手動關閉ac */ ((ClassPathXmlApplicationContext)ac).close(); } }測試類
執行test,列印結果如下:
INFO [AbstractApplicationContext.java:prepareRefresh:573]- Refreshing org[email protected]ba4d54: startup date [Fri Dec 14 11:41:09 CST 2018]; root of context hierarchy
INFO [XmlBeanDefinitionReader.java:loadBeanDefinitions:317]- Loading XML bean definitions from class path resource [applicationContext.xml]
Step1.執行構造方法...
Step2:執行aDao的setter方法...
Step2:執行bDao的setter方法...
Step3:獲取bean的id = implement
Step4:獲取到BeanFactory容器...
Step5:初始化完畢之前,執行before方法...
Step6:標誌著bean已經初始化完畢...
Step7:bean生命開始...
Step8:初始化完畢之後,執行after方法...
Step9:執行真正的業務處理邏輯doSome()方法...
INFO [AbstractApplicationContext.java:doClose:951]- Closing org[email protected]ba4d54: startup date [Fri Dec 14 11:41:09 CST 2018]; root of context hierarchy
Step10:實現介面的銷燬之前...
Step11:Bean銷燬之前...
列印結果
分析:
在注入一個bean時,大致經過了11個步驟。這個流程對每一個注入的bean都適用。BeanNameAware, BeanFactoryAware, InitializingBean, DisposableBean, BeanPostProcessor是spring中自帶的bean見名知意,在bean初始化、呼叫和銷燬之際被spring自動呼叫。
我們可以通過實現(如上面的MyImplement)這些容器中自動呼叫的bean介面類中的抽象方法來實現功能的擴充套件,並交由spring自動處理。可見,spring在注入一個我們自寫的bean時,建立了一個動態代理物件,這個物件不僅僅封裝了我們自己的介面實現類,也封裝了spring預設的這些介面實現類,從而完成了一個bean注入的整個生命週期。
當然,我們可以把Implement實現的這些介面單獨拿出來寫一個實現類,注入到spring容器中。以BeanPostProcessor為例。
package com.boke; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String s) throws BeansException { System.out.println("Step5:初始化完畢之前,執行before方法..."); return bean; // 要返回這個bean,它表示當前正在初始化的bean物件 } @Override public Object postProcessAfterInitialization(Object bean, String s) throws BeansException { System.out.println("Step8:初始化完畢之後,執行after方法..."); return bean; // 要返回這個bean,它表示當前正在初始化的bean物件 } }MyBeanPostProcessor
將其注入到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"> <!--測試生命bean--> <bean id="implement" class="com.boke.MyImplement" init-method="setUp" destroy-method="tearDown" > <!--初始化ISomeServiceImpl的成員變數--> <property name="aDao" value="aaa" /> <property name="bDao" value="bbb" /> </bean> <bean class="com.node.service.beanlife.MyBeanPostProcessor" /> </beans>applicationContext.xml
效果和直接繼承實現是一樣的。
在這些步驟中,我們可以定製一些針對所有bean都適用的功能來進行擴充套件。
BeanPostProcessor說明:
Bean後處理器是一種特殊的Bean,容器中所有的Bean在初始化時均會自動執行該類的兩個方法。由於該Bean是由其它Bean自動呼叫執行,不是程式設計師手工呼叫,故此Bean無須id屬性。Bean後處理器是org.springframework.beans.factory.config.BeanPostProcessor,它會被自動載入,並執行它的實現類的兩個方法:
public Object postProcessBeforeInitialization(Object bean, String beanId) throws BeanException,該方法會在目標Bean初始化完畢之前由容器自動呼叫。
public Object postProcessAfterInitialization(Object bean, String BeanId) throws BeansException,該方法會在目標Bean初始化完畢之後由容器自動呼叫。
它們的引數是:第一個引數是系統即將初始化的Bean例項,第二個引數是該Bean例項的id屬性值,若Bean沒有id就是name屬性值。實現類需要重寫這兩個方法,並註冊到bean中,spring容器會在每個bean呼叫之前(之後)自動執行者兩個方法。
四、基於XML的DI
applicationContext.xml中以bean標籤的方式注入屬於典型的xml方式的注入。上節梳理了bean注入的生命始末,本節記錄注入bean的一些方式。
1.無參構造注入
// Student類 package com.boke; public class Student { private String name; private int age; private School school; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public School getSchool() { return school; } public void setSchool(School school) { this.school = school; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", school=" + school + '}'; } } // School類 package com.boke; public class School { private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } @Override public String toString() { return "School{" + "name='" + name + '\'' + '}'; } }實體類
<?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"> <!--註冊無參構造的bean並注入成員變數--> <bean id="school" class="com.boke.School"> <property name="name" value="清華大學" /> </bean> <bean id="student" class="com.boke.Student"> <!--注入成員變數的值--> <property name="name" value="Alex" /> <property name="age" value="20" /> <!--對於一個物件,稱為域屬性,需要用ref來注入--> <property name="school" ref="school" /> </bean> </beans>applicationContext.xml
package com.node.boke; import com.boke.School; import com.boke.Student; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { @Test public void test01(){ ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); Student student = (Student)ac.getBean("student"); School school = (School)ac.getBean("school"); System.out.println(student); System.out.println(school); } }test
2.有參構造注入
// Student類 package com.boke; public class Student { private String name; private int age; private School school; Student(){ super(); } Student(String name, int age, School school){ super(); this.name = name; this.age = age; this.school = school; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public School getSchool() { return school; } public void setSchool(School school) { this.school = school; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", school=" + school + '}'; } } // School類 package com.boke; public class School { private String name; School(){ super(); } School(String name){ super(); this.name = name; } public void setName(String name) { this.name = name; } public String getName() { return name; } @Override public String toString() { return "School{" + "name='" + name + '\'' + '}'; } }實體類(POJO)
<?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"> <!--註冊有參構造的bean 不常用 --> <bean id="school" class="com.boke.School"> <property name="name" value="北京大學" /> </bean> <bean id="student" class="com.boke.Student"> <constructor-arg index="0" value="Alex" /> <constructor-arg index="1" value="24" /> <constructor-arg index="2" ref="school" /> </bean> </beans>applicationContext.xml
test測試程式碼和上面的一樣。
3.名稱空間注入:p模式
實體類不變,測試程式碼不變。
<?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.p名稱空間注入 需要在開頭的bean中引入xmlns:p="http://www.springframework.org/schema/p" --> <bean id="school" class="com.boke.School" p:name="北京大學" /> <bean id="student" class="com.boke.Student" p:name="張三" p:age="28" p:school-ref="school" /> </beans>applicationContext.xml
4.名稱空間注入:c模式
實體類不變,測試程式碼不變。
<?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:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--名稱空間注入 1.p名稱空間注入 需要在開頭的bean中引入xmlns:p="http://www.springframework.org/schema/p" --> <bean id="school" class="com.boke.School" c:name="北京大學" /> <bean id="student" class="com.boke.Student" c:name="張三" c:age="28" c:school-ref="school" /> </beans>applicationContext.xml
5.域屬性的自動注入
實體類不變,測試程式碼不變。
<?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:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="school" class="com.boke.School" c:name="北京大學" /> <!--autowire自動注入:會在容器中自動查詢名稱相同的bean注入 byName,根據bean名稱匹配查詢自動注入 byType,根據bean型別匹配查詢自動注入,具有is-a關係的bean,即除了本類還包括子類 --> <bean id="student" class="com.boke.Student" autowire="byName"> <property name="name" value="Weiweian" /> <property name="age" value="250" /> </bean> </beans>applicationContext.xml
6.集合注入
Student類和School類不變。
package com.boke; import java.util.*; public class Some { private School[] schools; private String[] strings; private List<String> list; private Set&