前言:談談對springIOc的理解,兩張圖很好的闡述了springIoc容器的作用。

傳統應用程序示意圖.jpg

IoC容器后程序結構示意圖.jpg
springIoC容器注入方式有set注入,構造器注入,注解注入。
一:set方式注入
1.先准備幾個bean類,一個普通的學生類,以及一個A類,A類組合了學生類對象。
Student.java
package com.cnblogs.bean; public class Student { // 學號
private String sNo; private String name; private int age; // 性別
private String sex; //年級
private String grade; public Student() { super(); } public Student(String sNo, String name, int age, String sex, String grade) { super(); this.sNo = sNo; this.name = name; this.age = age; this.sex = sex; this.grade = grade; }
// set和get方法
// toString方法()
}
A.java
package com.cnblogs.bean; public class A { private String desc; private Student stu; public A() { super(); // TODO Auto-generated constructor stub
} public A(String desc, Student stu) { super(); this.desc = desc; this.stu = stu; } // set和get方法
// toString方法() }
set.xml中
<!-- 基於set方法的注入 -->
<bean name="stu" class="com.cnblogs.bean.Student">
<property name="sNo" value="1001"></property>
<property name="name" value="jack"></property>
<property name="age" value="12"></property>
<property name="sex" value="male"></property>
<property name="grade" value="三年級"></property>
</bean>
<!-- 注入引用類型 -->
<bean name="A" class="com.cnblogs.bean.A">
<property name="desc" value="A組合了Student類對象"></property>
<!-- ref屬性表示調用這個setStudent方法的時候要用的參數是名字為stu的對象 -->
<property name="stu" ref="stu"></property>
</bean>
1.<bean>標簽中,name和id起標識這個對象的作用,id會幫我們檢查給對象起的名字是否規范(名字不能重復,不能有空格,不能已數字開頭),name不會檢查這些東西。
class屬性是一個類的全限定名,標識配置那個類。
2.springIoC默認是已單例模式管理對象,即通過相同的名字多次拿出來的對象一樣,可以再<bean>標簽中加屬性 scope="prototype"代表非單例,
scope="Singleton"代表單例模式。
3.可以給某一個對象加別名,在</bean>后面加一條<alias name="stu" alias="s1"/>。可以通過stu拿對象,也可以通過s1 拿對象。
4.當類中的一個成員變量為另一個類的對象時,在<property>子標簽中可以通過ref引入,ref的值為一個<bean>標簽的name或id值。
5.同一個類可以配置多個對象,但是標識多個對象的id或name值要不同。
注意:set方式底層會用到一個bean類的set方法,如果bean類的成員變量沒有set方法卻采用了set方式注入會報錯。
測試方法:
/** * 基於set方法的注入 */ @Test public void set(){ try{ String[] path = {"com/cnblogs/ioc/set/set.xml"}; ApplicationContext container = new ClassPathXmlApplicationContext(path); Student stu = (Student)container.getBean("stu"); System.out.println(stu); Object a = container.getBean("A"); System.out.println(a); } catch(Exception e) { e.printStackTrace(); } }
結果:
Student [sNo=1001, name=jack, age=12, sex=male, grade=三年級]
A [desc=A組合了Student類對象, stu=Student [sNo=1001, name=jack, age=12, sex=male, grade=三年級]]
2.set方式注入之集合的注入
(1)准備一個B類,里面包括了各種集合:list,set,map,property
B.java
package com.cnblogs.bean; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; public class B { // list集合
private List<String> list; // set集合
private Set<String> set; // map
private Map<String,String> map; // prop
private Properties prop; // set和get方法 }
collection.xml
<!-- 集合的注入 --> <bean name="coll" class="com.cnblogs.bean.B"> <!-- list集合 --> <property name="list"> <list> <value>jack</value> <value>tom</value> <value>tina</value> </list> </property> <!-- set集合 --> <property name="set"> <set> <value>1001</value> <value>1002</value> <value>1003</value> </set> </property> <!-- map集合 --> <property name="map"> <map> <entry key="name" value="zhangsan"></entry> <entry key="age" value="12"></entry> <entry key="gender" value="male"></entry> </map> </property> <!-- properties集合注入 --> <property name="prop"> <props> <prop key="driver">com.mysql.jdbc.Driver</prop> <prop key="username">study</prop> </props> </property> </bean>
測試方法:和上面那個一樣,就是xml的文件路徑改一下。
(2):如果一個list集合的泛型是一個類,也可以注入。
HobbyGroup.java
package com.cnblogs.bean; import java.util.List; // 興趣小組
public class HobbyGroup { private Long id; private String name; private List<Student> stu; public HobbyGroup() { super(); // TODO Auto-generated constructor stub
} public HobbyGroup(Long id, String name, List<Student> stu) { super(); this.id = id; this.name = name; this.stu = stu; }
// set和get方法
// toString方法() }
collection.xml
<bean name="hg" class="com.cnblogs.bean.HobbyGroup"> <property name="id" value="1"></property> <property name="name" value="羽毛球興趣小組"></property> <property name="stu"> <list> <bean name="stu1" class="com.cnblogs.bean.Student" > <property name="sNo" value="1001"></property> <property name="name" value="jack"></property> <property name="age" value="12"></property> <property name="sex" value="male"></property> <property name="grade" value="三年級"></property> </bean> <bean name="stu2" class="com.cnblogs.bean.Student"> <property name="sNo" value="1002"></property> <property name="name" value="tom"></property> <property name="age" value="13"></property> <property name="sex" value="male"></property> <property name="grade" value="三年級"></property> </bean> <bean name="stu3" class="com.cnblogs.bean.Student"> <property name="sNo" value="1003"></property> <property name="name" value="tina"></property> <property name="age" value="11"></property> <property name="sex" value="female"></property> <property name="grade" value="三年級"></property> </bean> </list> </property> </bean>
3.set注入之自動注入
1.自動注入一般針對一個類中組合了另一類的對象。
2.自動注入有byName注入和byType注入
3.byName注入:spring容器會到當前的類中找property的名字,然后再根據這個名字去spring容器中找有沒有和這個property名字相同的對象,有的話,
就把這個對象當做參數放到setXxxx這個方法里面注入進來。(找到多個不會報錯)
4.byType注入:spring容器會根據set方法的參數類型去容器中找相匹配的對象,找到就注入,沒找到就算了。如果找到多個會報錯。
5.可以在<beans>標簽中加 default-autowire="byType",則下面的標簽會根據byType方式自動注入。
6.可以在<bean>標簽中autowire=" "指定注入方式,該方式會屏蔽 default-autowire=" "。
示例:
同樣用到com.cnblogs.bean.A類和com.cnblogs.bean.Student類。
autowired.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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd" default-autowire="byName"
>
<bean name="stu" class="com.cnblogs.bean.Student">
<property name="sNo" value="1001"></property>
<property name="name" value="jack"></property>
<property name="age" value="12"></property>
<property name="sex" value="male"></property>
<property name="grade" value="三年級"></property>
</bean>
<!-- byName -->
<bean name="A1" class="com.cnblogs.bean.A">
<property name="desc" value="A組合了Student類對象,byName"></property>
</bean>
<!-- byType -->
<bean name="A2" class="com.cnblogs.bean.A" autowire="byType">
<property name="desc" value="A組合了Student類對象,byType"></property>
</bean>
</beans>
測試方法:
@Test public void autowired(){ try{ String[] path = {"com/cnblogs/ioc/autowired/autowired.xml"}; ApplicationContext container = new ClassPathXmlApplicationContext(path); // byName A a1 = (A) container.getBean("A1"); System.out.println(a1); // byType A a2 = (A) container.getBean("A2"); System.out.println(a2); } catch(Exception e) { e.printStackTrace(); } }
結果:
A [desc=A組合了Student類對象,byName, stu=Student [sNo=1001, name=jack, age=12, sex=male, grade=三年級]]
A [desc=A組合了Student類對象,byType, stu=Student [sNo=1001, name=jack, age=12, sex=male, grade=三年級]]
二:構造器注入
構造器有分兩種注入方式,一個根據參數類型注入,一個根據下標注入。
1.根據參數類型注入
同樣用到com.cnblogs.bean.Student類。
constructor.xml
<!-- 根據參數類型 -->
<bean name="stu1" class="com.cnblogs.bean.Student">
<constructor-arg type="String" value="1001"></constructor-arg>
<constructor-arg type="String" value="jack"></constructor-arg>
<constructor-arg type="int" value="12"></constructor-arg>
<constructor-arg type="String" value="male"></constructor-arg>
<constructor-arg type="String" value="三年級"></constructor-arg>
</bean>
2.根據參數下標注入
<!-- 根據下標 --> <bean name="stu2" class="com.cnblogs.bean.Student"> <constructor-arg index="0" value="1002"></constructor-arg> <constructor-arg index="1" value="tina"></constructor-arg> <constructor-arg index="2" value="12"></constructor-arg> <constructor-arg index="3" value="female"></constructor-arg> <constructor-arg index="4" value="三年級"></constructor-arg> </bean>
三、注解注入
首先需要在xml文件中指定使用注解注入的包,springIoC容器讀取這個文件的時候就會知道。
anatation.xml:
<context:component-scan base-package="com.cnblogs.ioc.anatation" />
com.cnblogs.ioc.annotation.Office.java
package com.cnblogs.ioc.anatation; import org.springframework.stereotype.Component; @Component public class Office { private String num = "001"; public Office(){ } public Office(String num) { this.num = num; } public String getNum() { return num; } public void setNum(String num) { this.num = num; } }
com.cnblogs.ioc.annotation.Car.java
package com.cnblogs.ioc.anatation;
import org.springframework.stereotype.Component;
@Component public class Car { private double price; private String name; public Car(){ } public Car(double price, String name) { this.price = price; this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
com.cnblogs.ioc.annotation.Boss.java
package com.cnblogs.ioc.anatation; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.annotation.Resource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @Component @Scope("prototype") public class Boss { private String name; @Autowired private Car car; @Resource private Office office; public Boss(){ } public Boss(String name, Car car, Office office) { this.name = name; this.car = car; this.office = office; } public Boss( Car car, Office office) { this.car = car; this.office = office; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } public Office getOffice() { return office; } public void setOffice(Office office) { this.office = office; } @PostConstruct public void init(){ System.out.println("初始化.."); } @PreDestroy public void destory(){ System.out.println("銷毀..."); } }
測試方法:
/** * 注解注入 */ @Test public void anatation(){ try{ String[] path = {"com/cnblogs/ioc/anatation/anatation.xml"}; ApplicationContext container = new ClassPathXmlApplicationContext(path); Boss boss = (Boss) container.getBean("boss"); System.out.println(boss.getName()); System.out.println(boss.getCar()); System.out.println(boss.getOffice()); System.out.println(boss); } catch(Exception e) { e.printStackTrace(); } }
結果
初始化..
null
com.cnblogs.ioc.anatation.Car@50de0926
com.cnblogs.ioc.anatation.Office@2473b9ce
com.cnblogs.ioc.anatation.Boss@60438a68
幾個注解的作用:
@Autowired 1) @Autowired使用后需要在xml文件加入以下配置才能生效: <context:annotation-config/> 2) @Autowired注解可以寫在成員變量、setter方法、構造器函數上面 3) @Autowired默認按照byType匹配的方式進行注入,如果沒有一個bean的類型是匹配的則會拋異常,如果有多個bean的類型都匹配成功了, 那么再按byName方式進行選擇 4) @Autowired如果最終匹配不成功(注意一定是一個都沒有找到的情況)則會拋出異常,但是如果設置為 @Autowired(required=false), 則最終匹配不成功沒有不會拋出異常。 5) @Autowired可以結合@Qualifier("beanName")來使用,則可以達到byName的效果 @Resource 1) @Resource使用后需要在xml文件加入以下配置才能生效:<context:annotation-config/> 2) @Resource的作用和@Autowired差不多,只不過 @Resource是默認先用byName,如果找不到合適的就再用byType來注入 3) @Resource有倆個屬性,name和type,使用name屬性則表示要byName匹配,使用type屬性則表示要byType匹配 @PostConstruct和@PreDestroy 1) 標注了@PostConstruct注解的方法將在類實例化后調用 2) 標注了@PreDestroy注解的方法將在類銷毀之前調用 @Component 1) @Component注解可以直接定義bean,而無需在xml定義。但是若兩種定義同時存在,xml中的定義會覆蓋類中注解的Bean定義 2) @Component注解直接寫在類上面即可 3) @Component有一個可選的參數,用於指定bean的名稱 @Component("boss") public class Boss{} 4) @Component如果不指定參數,則bean的名稱為當前類的類名小寫 //和上面例子的相關相同 @Component public class Boss{} 5) @Component使用之后需要在xml文件配置一個標簽 <context:component-scan/> 6) <context:component-scan base-package="com.briup.ioc.annotation" /> 表示spring檢查指定包下的java類,看它們是否使用了 @Component注解 7) @Component定義的bean默認情況下都是單例模式的,如果要讓這個bean變為非單例,可以再結合這個@Scope注解來達到目標@Scope("prototype") @Component是Spring中所有bean組件的通用形式, @Repository @Service @Controller 則是 @Component的細化,用來表示更具體的用例, 分別對應了持久化層、服務層和表現層。但是至少到現在為止這個四種注解的實質區別很小(甚至幾乎沒有),都是把當前類注冊為spring容器中 的一個bean 注意: 1.component-scan標簽默認情況下自動掃描指定路徑下的包(含所有子包) 2.component-scan標簽將帶有@Component @Repository @Service @Controller注解的類自動注冊到spring容器中 3.component-scan標簽對標記了@Required @Autowired @PostConstruct @PreDestroy @Resource @WebServiceRef @EJB @PersistenceContext @PersistenceUnit等注解的類進行對應的操作,使注解生效 4.component-scan標簽包含了annotation-config標簽的作用
