Spring管理Bean-IOC
1.Spring配置/管理bean介紹
- Bean管理包括兩方面:
- 建立bean物件
- 給bean注入屬性
- Bean的配置方式:
- 基於xml檔案配置方式
- 基於註解配置方式
2.基於XML配置bean
2.1透過型別來獲取bean
透過id來獲取bean在Spring基本介紹中已經使用過,這裡不再贅敘
2.1.1應用案例
-
案例說明:
- 透過spring的ioc容器,獲取一個bean物件
- 說明:獲取bean的方式:按型別
-
完成步驟:
- 建立一個Java物件Monster.java
- 在beans.xml中配置
Monster.java:
package com.li.bean;
/**
* @author 李
* @version 1.0
* Javabean / Entity
*/
public class Monster {
private Integer monsterId;
private String name;
private String skill;
//無參構造器一定要有,spring底層反射建立物件時需要使用
public Monster() {
}
public Monster(Integer monsterId, String name, String skill) {
this.monsterId = monsterId;
this.name = name;
this.skill = skill;
}
public Integer getMonsterId() {
return monsterId;
}
public void setMonsterId(Integer monsterId) {
this.monsterId = monsterId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSkill() {
return skill;
}
public void setSkill(String skill) {
this.skill = skill;
}
@Override
public String toString() {
return "Monster{" +
"monsterId=" + monsterId +
", name='" + name + '\'' +
", skill='" + skill + '\'' +
'}';
}
}
beans.xml:
<!--配置Monster,希望透過型別來獲取-->
<bean class="com.li.bean.Monster" >
<property name="monsterId" value="10086"/>
<property name="name" value="孫悟空"/>
<property name="skill" value="筋斗雲"/>
</bean>
SpringBeanTest:
package com.li.test;
import com.li.bean.Monster;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.Test;
/**
* @author 李
* @version 1.0
*/
public class SpringBeanTest {
//透過Bean的型別來獲取物件
@Test
public void getBeanByType() {
ApplicationContext ioc =
new ClassPathXmlApplicationContext("beans.xml");
//直接傳入class物件/型別
Monster bean = ioc.getBean(Monster.class);
System.out.println(bean);
}
}
2.1.2細節說明
-
按照型別來獲取bean,要求ioc容器中的同一個類的bean只能有一個,否則會丟擲異常NoUniqueBeanDefinitionException
-
用型別來獲取bean的應用場景:XxxAction/Servlet/Controller或者XxxService,在一個執行緒中只需要一個物件例項的情況(單例情況)
-
在容器配置檔案(比如beans.xml)中給屬性值,底層是透過setter方法完成的,這也是為什麼需要在java物件中提供setter方法,否則會報錯
2.2透過構造器配置bean
2.2.1應用例項
-
案例說明:
使用spring的ioc容器,可以透過構造器來來配置bean物件
-
完整步驟:
- 配置bean.xml
在beans.xml配置:
前提是Monster類中有對應的構造器
<!--配置Monster物件,並指定構造器-->
<!--
1. constructor-arg 標籤可以指定使用構造器的引數
2. index 表示構造器的第幾個引數,從0開始計算
3. 除了透過index,還可以透過 name/ type 的方式來指定引數
4. 類構造器可以有多個,但是不能有引數完全相同的型別和順序的構造器,
這就決定了 透過構造器引數type 可以唯一確定一個構造器)
-->
<bean id="monster03" class="com.li.bean.Monster">
<constructor-arg value="200" index="0"/>
<constructor-arg value="白骨精" index="1"/>
<constructor-arg value="吸血" index="2"/>
</bean>
<!--透過 name 的方式來指定引數-->
<bean id="monster04" class="com.li.bean.Monster">
<constructor-arg value="200" name="monsterId"/>
<constructor-arg value="白骨精" name="name"/>
<constructor-arg value="吸血" name="skill"/>
</bean>
<!--透過 type 的方式來指定引數-->
<bean id="monster05" class="com.li.bean.Monster">
<constructor-arg value="200" type="java.lang.Integer"/>
<constructor-arg value="白骨精" type="java.lang.String"/>
<constructor-arg value="吸血" type="java.lang.String"/>
</bean>
SpringBeanTest:
package com.li.test;
import com.li.bean.Monster;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.Test;
import java.io.File;
/**
* @author 李
* @version 1.0
*/
public class SpringBeanTest {
//透過構造器來設定屬性
@Test
public void setBeanConstructor() {
ApplicationContext ioc =
new ClassPathXmlApplicationContext("beans.xml");
Monster monster03 = ioc.getBean("monster03", Monster.class);
System.out.println("monster03=" + monster03);
}
}
2.2.2細節說明
- 透過index屬性來區分是第幾個引數
- 透過type屬性來區分是什麼型別(按照順序)
2.3透過p名稱空間配置bean
2.3.1應用例項
-
案例說明:
在spring的ioc容器,可以透過p名稱空間來配置bean物件
-
完成步驟:
- 在beans.xml配置,增加名稱空間配置,如下,點選Create namespace declaration,成功後在配置檔案頭會自動新增xmlns
beans.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">
<!--透過p名稱空間來配置bean
將游標放在p,輸入alt+enter,就會自動新增 xmlns
-->
<bean id="monster06" class="com.li.bean.Monster"
p:monsterId="500"
p:name="紅孩兒"
p:skill="風火輪"
/>
</beans>
SpringBeanTest:
package com.li.test;
import com.li.bean.Monster;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.Test;
/**
* @author 李
* @version 1.0
*/
public class SpringBeanTest {
//透過p名稱空間來設定屬性
@Test
public void setBeanByP() {
ApplicationContext ioc =
new ClassPathXmlApplicationContext("beans.xml");
Monster monster06 = ioc.getBean("monster06", Monster.class);
System.out.println("monster06=" + monster06);
}
}
2.3.2細節說明
注意要引入p名稱空間
2.4引用/注入其他bean物件
2.4.1應用例項
-
案例說明:
在spring的ioc容器中,可以透過 ref (reference)來實現bean物件的相互應用
-
完成步驟:
- 建立MemberDAOImpl.java,MemberServiceImpl.java
- 配置beans.xml
beans.xml:
<!--配置MemberDAOImpl物件-->
<bean class="com.li.dao.MemberDAOImpl" id="memberDAO"/>
<!--配置MemberServiceImpl物件
1.ref="memberDAO" 表示
MemberServiceImpl 物件的屬性memberDAO 引用的物件是id=memberDAO的物件
2.這就體現了spring容器的依賴注入
3.注意在spring容器中,是作為一個整體來執行的,也就是說如果你引用到了一個bean物件,對你配置的順序沒有要求
(在底層,對spring配置檔案進行掃描,將關聯的關係自動梳理,並放到beanDefinitionMap中,
也就是說,是從beanDefinitionMap中查詢關聯關係的。與spring配置檔案的配置順序無關)
4.但是建議按照順序配置,易於閱讀
-->
<bean class="com.li.service.MemberServiceImpl" id="memberService">
<property name="memberDAO" ref="memberDAO"/>
</bean>
MemberDAOImpl:
package com.li.dao;
/**
* @author 李
* @version 1.0
* DAO 物件
*/
public class MemberDAOImpl {
//構造器
public MemberDAOImpl() {
System.out.println("MemberDAOImpl 構造器...");
}
//方法
public void add() {
System.out.println("MemberDAOImpl add()方法被執行");
}
}
MemberServiceImpl:
package com.li.service;
import com.li.dao.MemberDAOImpl;
/**
* @author 李
* @version 1.0
* Service類
*/
public class MemberServiceImpl {
private MemberDAOImpl memberDAO;
public MemberDAOImpl getMemberDAO() {
return memberDAO;
}
public void setMemberDAO(MemberDAOImpl memberDAO) {
this.memberDAO = memberDAO;
}
public void add() {
System.out.println("MemberServiceImpl add() 方法被呼叫...");
memberDAO.add();
}
}
SpringBeanTest:
package com.li.test;
import com.li.service.MemberServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.Test;
/**
* @author 李
* @version 1.0
*/
public class SpringBeanTest {
//透過ref 來設定 bean屬性
@Test
public void setBeanByRef() {
ApplicationContext ioc =
new ClassPathXmlApplicationContext("beans.xml");
MemberServiceImpl memberService =
ioc.getBean("memberService", MemberServiceImpl.class);
memberService.add();
}
}
2.4.2細節說明
注意:在spring容器中,是作為一個整體來執行的,也就是說如果你引用到了一個bean物件,對你配置的順序沒有要求。例如這裡的例子,如果我們將Memb erDAOImpl物件的配置,放到MemberServiceImpl物件的配置之後也是可以的。
因為在底層,會對spring的配置檔案進行掃描,將關聯的關係自動梳理,並放到beanDefinitionMap中。
也就是說,是從beanDefinitionMap中查詢關聯關係的。與spring配置檔案的配置順序無關。
但是建議按照順序配置,易於閱讀
2.5引入/注入內部bean物件
2.5.1應用例項
-
案例說明:
在spring的ioc容器中,可以直接配置內部bean物件
-
完成步驟:
- 建立MemberDAOImpl.java,MemberServiceImpl.java
- 配置beans.xml
建立MemberDAOImpl.java,MemberServiceImpl.java(見2.4)
beans.xml:
<!--配置MemberService物件(使用內部bean)-->
<bean class="com.li.service.MemberServiceImpl" id="memberService2">
<!--自己配置一個內部bean-->
<property name="memberDAO">
<bean class="com.li.dao.MemberDAOImpl"/>
</property>
</bean>
SpringBeanTest:
package com.li.test;
import com.li.service.MemberServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.Test;
/**
* @author 李
* @version 1.0
*/
public class SpringBeanTest {
//透過內部 bean來設定 bean屬性
@Test
public void setBeanByProper() {
ApplicationContext ioc =
new ClassPathXmlApplicationContext("beans.xml");
MemberServiceImpl memberService2 =
ioc.getBean("memberService2", MemberServiceImpl.class);
memberService2.add();
}
}
2.6引用/注入集合/陣列型別
2.6.1應用例項
-
案例說明
在spring的ioc容器中,看看如何給bean物件的集合/陣列型別屬性賦值
-
完成步驟:
- 建立Monster.java
- 建立Master.java
- 配置beans.xml
Monster.java:見2.1
Master.java:
package com.li.bean;
import java.util.*;
/**
* @author 李
* @version 1.0
* Master類
*/
public class Master {
private String name;
private List<Monster> monsterList;
private Map<String, Monster> monsterMap;
private Set<Monster> monsterSet;
//陣列
private String[] monsterName;
// Properties 是 Hashtable 的子類,也是k-v形式
// 這裡Properties 的key和value都是String型別
private Properties pros;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Monster> getMonsterList() {
return monsterList;
}
public void setMonsterList(List<Monster> monsterList) {
this.monsterList = monsterList;
}
public Map<String, Monster> getMonsterMap() {
return monsterMap;
}
public void setMonsterMap(Map<String, Monster> monsterMap) {
this.monsterMap = monsterMap;
}
public Set<Monster> getMonsterSet() {
return monsterSet;
}
public void setMonsterSet(Set<Monster> monsterSet) {
this.monsterSet = monsterSet;
}
public String[] getMonsterName() {
return monsterName;
}
public void setMonsterName(String[] monsterName) {
this.monsterName = monsterName;
}
public Properties getPros() {
return pros;
}
public void setPros(Properties pros) {
this.pros = pros;
}
@Override
public String toString() {
return "Master{" +
"name='" + name + '\'' +
", monsterList=" + monsterList +
", monsterMap=" + monsterMap +
", monsterSet=" + monsterSet +
", monsterName=" + Arrays.toString(monsterName) +
", pros=" + pros +
'}';
}
}
beans.xml:
<!--配置Master物件-->
<!--體會Spring容器配置特點-->
<bean class="com.li.bean.Master" id="master">
<property name="name" value="太上老君"/>
<!--(1)給list屬性賦值-->
<property name="monsterList">
<list>
<!--方式1.引用的方式-->
<ref bean="monster01"/>
<ref bean="monster02"/>
<!--方式2.內部bean-->
<bean class="com.li.bean.Monster">
<property name="name" value="黃袍怪"/>
<property name="monsterId" value="1024"/>
<property name="skill" value="吃人"/>
</bean>
</list>
</property>
<!--(2)給map屬性賦值-->
<property name="monsterMap">
<map>
<entry>
<key>
<value>monster01</value>
</key>
<!--也可以透過內部 bean來配置,這裡使用引用-->
<ref bean="monster01"/>
</entry>
<entry>
<key>
<value>monster02</value>
</key>
<!--也可以透過內部 bean來配置,這裡使用引用-->
<ref bean="monster02"/>
</entry>
</map>
</property>
<!--(3)給set屬性賦值-->
<property name="monsterSet">
<set>
<!--同理,依然可以使用ref或者內部 bean的方式配置-->
<ref bean="monster05"/>
<bean class="com.li.bean.Monster">
<property name="name" value="金角大王"/>
<property name="monsterId" value="888"/>
<property name="skill" value="有錢"/>
</bean>
</set>
</property>
<!--(4)給陣列屬性賦值-->
<property name="monsterName">
<array>
<!--這裡根據陣列的型別來選擇對應的標籤-->
<value>小豬妖</value>
<value>大鵬妖</value>
<value>老狐狸</value>
<!--同理,依然可以使用ref或者內部 bean的方式配置-->
</array>
</property>
<!--(5)給Properties屬性賦值,結構 k(String)-v(String)-->
<property name="pros">
<props>
<prop key="username">root</prop>
<prop key="pwd">1234</prop>
<prop key="ip">127.0.0.1</prop>
</props>
</property>
</bean>
SpringBeanTest:
package com.li.test;
import com.li.bean.Master;
import com.li.bean.Monster;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.Test;
import java.util.Iterator;
import java.util.Map;
/**
* @author 李
* @version 1.0
*/
public class SpringBeanTest {
//給集合/陣列屬性進行配置值
@Test
public void setBeanByCollection() {
ApplicationContext ioc =
new ClassPathXmlApplicationContext("beans.xml");
Master master = ioc.getBean("master", Master.class);
System.out.println("========master的list屬性=========");
for (Monster monster : master.getMonsterList()) {
System.out.println(monster);
}
System.out.println("\n========master的map屬性=========");
Iterator<Map.Entry<String, Monster>> iterator =
master.getMonsterMap().entrySet().iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
System.out.println("\n========master的set屬性=========");
for (Monster monster : master.getMonsterSet()) {
System.out.println(monster);
}
System.out.println("\n========master的陣列屬性=========");
for (int i = 0; i < master.getMonsterName().length; i++) {
System.out.println(master.getMonsterName()[i]);
}
System.out.println("\n========master的Properties屬性=========");
Iterator<Map.Entry<Object, Object>> iterator1
= master.getPros().entrySet().iterator();
while (iterator1.hasNext()) {
System.out.println(iterator1.next());
}
}
}
2.6.2細節說明
-
主要掌握List/Map/Properties三種集合的使用
-
Properties集合的特點:
(1)Properties是Hashtable的子類,也是key-value形式
(2)key是String型別,value也是String型別