Spring管理Bean-IOC-02
2.基于XML配置bean
2.7通過util空間名稱創建list
BookStore.java:
package com.li.bean;
import java.util.List;
/**
* @author 李
* @version 1.0
*/
public class BookStore {
private List<String> bookList;
//如果類中沒有其他構造器,默認構造器可以不寫
// 如果有其他構造器,則必須顯示定義無參構造器
public BookStore() {
}
public List<String> getBookList() {
return bookList;
}
public void setBookList(List<String> bookList) {
this.bookList = bookList;
}
@Override
public String toString() {
return "BookStore{" +
"bookList=" + bookList +
'}';
}
}
如果有多個BookStore物件,list的內容都一樣,按照之前的做法,每一個list都要寫上相同的value值,但使用util命名空間可以達到資料復用的效果,
beans.xml:
<!--定義util:list,并指定id,可以達到資料復用的效果-->
<util:list id="myBookList">
<value>三國演義</value>
<value>紅樓夢</value>
<value>西游記</value>
<value>水滸傳</value>
</util:list>
<!--配置BookStores物件-->
<bean id="bookStore">
<property name="bookList" ref="myBookList"/>
</bean>
注意引入util命名空間,一般來說ide會有提示,如果沒有則按如下引入:
SpringBeanTest:
package com.li.test;
import com.li.bean.BookStore;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.Test;
/**
* @author 李
* @version 1.0
*/
public class SpringBeanTest {
//使用util:list名稱空間給屬性賦值
@Test
public void setBeanByUtilList() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
BookStore bookStore = ioc.getBean("bookStore", BookStore.class);
System.out.println("bookStore=" + bookStore);
}
}
2.8級聯屬性賦值
-
案例說明:spring的ioc容器,可以直接給物件屬性的屬性賦值,即級聯屬性賦值
-
完成步驟:
(1)創建Dept.java和Emp.java
(2)配置beans.xml
Dept.java:
package com.li.bean;
/**
* @author 李
* @version 1.0
* 部門類
*/
public class Dept {
private String name;
public Dept() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Dept{" +
"name='" + name + '\'' +
'}';
}
}
Emp.java:
package com.li.bean;
/**
* @author 李
* @version 1.0
* 員工類
*/
public class Emp {
private String name;
private Dept dept;
public Emp() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Emp{" +
"name='" + name + '\'' +
", dept=" + dept +
'}';
}
}
beans.xml:
<!--配置Dept物件-->
<bean id="dept"/>
<!--配置Emp物件-->
<bean id="emp">
<property name="name" value="https://www.cnblogs.com/liyuelian/archive/2023/01/17/jack"/>
<property name="dept" ref="dept"/>
<!--這里我希望給dept的name屬性賦值[級聯屬性賦值]-->
<property name="dept.name" value="https://www.cnblogs.com/liyuelian/archive/2023/01/17/Java開發部門"/>
</bean>
SpringBeanTest:
package com.li.test;
import com.li.bean.Emp;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.Test;
/**
* @author 李
* @version 1.0
*/
public class SpringBeanTest {
//使用級聯賦值給屬性的屬性賦值
@Test
public void setBeanByRelation() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Emp emp = ioc.getBean("emp", Emp.class);
System.out.println("emp=" + emp);
}
}
2.9通過靜態工廠獲取物件
-
在spring的ioc容器,可以通過靜態工廠獲取bean物件
-
完成步驟:
(1)靜態工廠類MyStaticFactory類和Monster類
(2)配置beans.xml
Monster類詳見上一篇--2.1通過型別來獲取bean
MyStaticFactory.java:
package com.li.factory;
import com.li.bean.Monster;
import java.util.HashMap;
import java.util.Map;
/**
* @author 李
* @version 1.0
* 靜態工廠類-可以回傳Monster物件
*/
public class MyStaticFactory {
private static Map<String, Monster> monsterMap;
//使用static靜態代碼塊進行初始化
// (靜態代碼塊在類加載的同時就直接執行,且只執行一次)
static {
monsterMap = new HashMap<>();
monsterMap.put("monster01", new Monster(100, "孫悟空", "七十二變"));
monsterMap.put("monster02", new Monster(200, "金蟬子", "普渡眾生"));
}
//提供一個方法,回傳monster物件
public static Monster getMonster(String key) {
return monsterMap.get(key);
}
}
beans.xml:
<!--配置monster,通過靜態工廠獲取
1.通過靜態工廠配置bean
2.class不再是monster的路徑,而是靜態工廠的全路徑
3.factory-method 表示指定靜態工廠的哪個方法來回傳物件
4.constructor-arg value="https://www.cnblogs.com/liyuelian/archive/2023/01/17/monster02" 指定要回傳靜態工廠的哪個物件
-->
<bean id="my_monster01" factory-method="getMonster">
<constructor-arg value="https://www.cnblogs.com/liyuelian/archive/2023/01/17/monster02"/>
</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 getBeanByStaticFactory() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Monster my_monster01 = ioc.getBean("my_monster01", Monster.class);
//這里如果使用的是相同id獲取bean,那么獲取的實際上是同一個物件,例如:
Monster my_monster001 = ioc.getBean("my_monster01", Monster.class);
// 因為靜態工廠中的靜態代碼塊只執行一次,這里不同的物件參考指向的都是同一個物件
System.out.println(my_monster01 == my_monster001);//true
System.out.println("my_monster01=" + my_monster01);
}
}
2.10通過實體工廠獲取物件
Monster類詳見上一篇--2.1通過型別來獲取bean
MyInstanceFactory:
package com.li.factory;
import com.li.bean.Monster;
import java.util.HashMap;
import java.util.Map;
/**
* @author 李
* @version 1.0
* 實體工廠類
*/
public class MyInstanceFactory {
private Map<String, Monster> monster_map;
//通過普通代碼塊進行初始化
//普通代碼塊每創建一個物件就會執行一次
{
monster_map = new HashMap<>();
monster_map.put("monster03", new Monster(300, "豬八戒", "九尺釘耙"));
monster_map.put("monster04", new Monster(400, "沙和尚", "丈二禪杖"));
}
//寫一個方法回傳Monster物件
public Monster getMonster(String key) {
return monster_map.get(key);
}
}
beans.xml:
<!--因為是實體工廠物件,所以需要配置才能使用(靜態工廠可以直接使用不用配置)-->
<bean id="myInstanceFactory"/>
<bean id="myInstanceFactory02"/>
<!--配置monster,通過實體工廠獲取
1.factory-bean 表示使用哪個實體工廠物件回傳bean
2.factory-method 指定使用實體工廠物件的哪個方法回傳bean
3.constructor-arg value="https://www.cnblogs.com/liyuelian/archive/2023/01/17/monster03" 指定獲取實體工廠中的哪個物件
-->
<bean id="my_monster02" factory-bean="myInstanceFactory" factory-method="getMonster">
<constructor-arg value="https://www.cnblogs.com/liyuelian/archive/2023/01/17/monster03"/>
</bean>
<bean id="my_monster03" factory-bean="myInstanceFactory02" factory-method="getMonster">
<constructor-arg value="https://www.cnblogs.com/liyuelian/archive/2023/01/17/monster03"/>
</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 getBeanByInstanceFactory() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Monster my_monster02 = ioc.getBean("my_monster02", Monster.class);
System.out.println("my_monster02=" + my_monster02);
// 這里使用相同的id獲取bean,那么回傳的物件也是同一個!!
Monster my_monster002 = ioc.getBean("my_monster02", Monster.class);
// 因為雖然是實體工廠,但是兩次 ioc.getBean("my_monster02", Monster.class)使用的都是
// 同一個工廠實體(id="myInstanceFactory"),回傳的自然也就是同一個實體工廠中的 monster
System.out.println(my_monster02 == my_monster002);//true
//換而言之,如果不是同一個實體工廠,那么回傳的就不是同一個物件了
//(這里的my_monster03,在beans.xml使用的是 id=myInstanceFactory02的實體工廠)
Monster my_monster03 = ioc.getBean("my_monster03", Monster.class);
System.out.println("my_monster03=" + my_monster03);
System.out.println(my_monster02 == my_monster03);//false
}
}
2.11通過FactoryBean獲取物件(重點)
在spring的ioc容器,通過FactoryBean獲取bean物件
MyFactoryBean:
package com.li.factory;
import com.li.bean.Monster;
import org.springframework.beans.factory.FactoryBean;
import java.util.HashMap;
import java.util.Map;
/**
* @author 李
* @version 1.0
* FactoryBean
*/
public class MyFactoryBean implements FactoryBean<Monster> {
//這個就是你配置的時候,指定要獲取的物件對應的key
private String key;
private Map<String, Monster> monster_map;
//代碼塊完成初始化
{
monster_map = new HashMap<>();
monster_map.put("monster05", new Monster(5, "黑風怪", "翻江倒海"));
monster_map.put("monster06", new Monster(6, "金角大王", "超能力"));
}
public void setKey(String key) {
this.key = key;
}
@Override
public Monster getObject() throws Exception {
return monster_map.get(key);
}
@Override
public Class<?> getObjectType() {
return Monster.class;
}
@Override
public boolean isSingleton() {//這里指定是否是單例物件
return true;
}
}
beans.xml:
<!--配置monster物件,通過FactoryBean來獲取
1.這里的class 指定要使用的FactoryBean
2.key是 你設定的FactoryBean的屬性key
3.value 就是你要獲取的物件的對應 key
-->
<bean id="my_monster05" >
<property name="key" value="https://www.cnblogs.com/liyuelian/archive/2023/01/17/monster05"/>
</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 {
//通過FactoryBean獲取bean物件
@Test
public void getBeanByFactoryBean() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Monster my_monster05 = ioc.getBean("my_monster05", Monster.class);
System.out.println("my_monster05=" + my_monster05);
}
}
2.12bean配置資訊重用(繼承)
在spring的ioc容器中,提供了一種繼承的方式來實作bean配置資訊的重用
beans.xml:
<!--配置Monster物件-->
<bean id="monster10">
<property name="monsterId" value="https://www.cnblogs.com/liyuelian/archive/2023/01/17/10"/>
<property name="name" value="https://www.cnblogs.com/liyuelian/archive/2023/01/17/蜈蚣精"/>
<property name="skill" value="https://www.cnblogs.com/liyuelian/archive/2023/01/17/蜇人"/>
</bean>
<!--現在配置另一個Monster物件,
1.這個物件的屬性值 和 id="monster10"物件屬性一樣
2.parent="monster10" 指定當前這個配置的物件的屬性值從id=monster10的物件來
-->
<bean id="monster11" parent="monster10"/>
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 getBeanByFactoryBean() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Monster monster10 = ioc.getBean("monster10", Monster.class);
Monster monster11 = ioc.getBean("monster11", Monster.class);
System.out.println("monster10=" + monster10);
System.out.println("monster11=" + monster11);
}
}
注意:
-
如果bean指定了abstract="true" 表示該bean物件是只用于被繼承的
-
那么這個bean就不能被獲取/實體化
此時如果輸出monster10,就會顯示錯誤:
2.13bean創建順序
在spring的ioc容器,默認是按照配置的順序創建bean物件,比如:
<bean id="student01" />
<bean id="department01" />
會先創建 student01 這個 bean 物件,然后創建 department01 這個 bean 物件
但如果這樣配置:
<bean id="student01" depends-on="department01"/>
<bean id="department01" />
會先創建 department01 物件,再創建 student01 物件.
例子
Student:
package com.li.bean;
/**
* @author 李
* @version 1.0
*/
public class Student {
public Student() {
System.out.println("Student 構造器被執行...");
}
}
Department:
package com.li.bean;
/**
* @author 李
* @version 1.0
*/
public class Department {
public Department() {
System.out.println("Department 構造器被執行...");
}
}
beans.xml:
<!--測驗 bean物件的創建順序-->
<bean id="student01" />
<bean id="department01" />
測驗類:
//測驗 Bean的創建順序
@Test
public void testBeanByCreate() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
System.out.println("ok~");
}
如果我們在配置student01物件時,加上depends-on="department01",spring就會認為你的student01物件時依賴于department01物件,會先創建department01物件,
<bean id="student01" depends-on="department01"/>
<bean id="department01" />
總結:在默認情況下,bean創建的順序是按照默認配置順序來的,但是如果我們在物件配置中指定了依賴物件,就會先創建被依賴的物件,
一個問題?
1.先看下面的配置,請問兩個bean創建的順序是什么?并分析執行流程
<!--配置MemberDAOImpl物件-->
<bean id="memberDAOImpl"/>
<bean id="memberServiceImpl">
<property name="memberDAO" ref="memberDAOImpl"/>
</bean>
(1)先創建 id=memberDaoImpl 的物件
(2)再創建 id=memberServiceImpl 的物件
(3)呼叫 memberServiceImpl.setMemberDAO() 方法,完成參考
2.先看下面的配置,請問兩個bean創建的順序是什么?并分析執行流程
<bean id="memberServiceImpl">
<property name="memberDAO" ref="memberDAOImpl"/>
</bean>
<!--配置MemberDAOImpl物件-->
<bean id="memberDAOImpl"/>
(1)先創建 id=memberServiceImpl 的物件
(2)再創建 id=memberDaoImpl 的物件
(3)呼叫 memberServiceImpl.setMemberDAO() 方法,完成參考
總結:ioc容器會把整個bean的創建當做一個整體來對待,會把組態檔中所有物件bean先創建好,然后才完成物件間的參考,
見2.4
2.14bean物件的單例和多例
在spring的ioc容器中,默認是按照單例創建的,即配置一個bean物件后,ioc容器只會創建一個bean實體,
如果希望ioc容器配置的某個bean物件,是以多個實體形式創建的,可以通過配置scope="prototype"來指定,
例子1-單例物件
Cat:
package com.li.bean;
/**
* @author 李
* @version 1.0
*/
public class Cat {
private Integer id;
private String name;
public Cat() {
System.out.println("Cat() 構造器被執行...");
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
beans.xml:
<!--配置 Cat物件
1.默認情況下,scope屬性的值為 "singleton",即ioc容器中只會有一個這樣的bean物件
當執行getBean時,回傳的是同一個物件
2.如果希望每次使用getBean都回傳新的Bean物件,就要把scope的屬性設為 prototype
-->
<bean id="cat" >
<property name="id" value="https://www.cnblogs.com/liyuelian/archive/2023/01/17/10"/>
<property name="name" value="https://www.cnblogs.com/liyuelian/archive/2023/01/17/小花貓"/>
</bean>
測驗類:
//測驗Scope
@Test
public void testBeanScope() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Cat cat1 = ioc.getBean("cat", Cat.class);
Cat cat2 = ioc.getBean("cat", Cat.class);
Cat cat3 = ioc.getBean("cat", Cat.class);
System.out.println("cat1="+cat1);
System.out.println("cat2="+cat2);
System.out.println("cat3="+cat3);
}
輸出如下:地址值相同,證明這三個物件參考都指向了同一個物件
例子2-多例物件
現在我們把例子1的cat物件的配置改為scope="prototype"
<bean id="cat" scope="prototype">
<property name="id" value="https://www.cnblogs.com/liyuelian/archive/2023/01/17/10"/>
<property name="name" value="https://www.cnblogs.com/liyuelian/archive/2023/01/17/小花貓"/>
</bean>
輸出如下:構造器執行了三次,說明創建了三個Cat物件(物件的地址值也不一樣)
使用細節
-
當bean為scope="singleton"(默認值),在啟動容器時,就會創建單例物件,并放入singletonObjects集合
-
當bean設定為scope="prototype",即設定為多實體機制后,該bean是在getBean時才創建
-
如果是單例singleton,但又希望在getBean時才創建,可以指定懶加載lazy-init="true" (默認值是false)
-
通常情況下,lazy-init 使用默認值false,因為在開發看來,用空間換時間是值得的,除非有特殊要求,
-
如果scope="prototype",這時你的lazy-init屬性值不管設定為什么,都默認為true
因為多例情況下,spring無法知道創建幾個物件,因此只有在用到的時候才能創建
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/542134.html
標籤:其他
上一篇:Spring6
