1、獲取bean實體的三種方式
1.1 id 屬性
1.1.1 jar
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>4.3.18.RELEASE</spring.version>
<lombok.version>1.16.18</lombok.version>
<junit.version>4.11</junit.version>
</properties>
<dependencies>
<!-- spring-beans begin -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- spring-beans end -->
<!-- spring-core begin -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- spring-core end -->
<!-- spring-context begin -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- spring-context end -->
<!-- spring-expression begin -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- spring-expression end -->
</dependencies>
1.1.2 application.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">
<!-- 基于spring的核心組態檔方式,手動配置一個bean,放到spring的容器中 -->
<bean id="userOne" >
<property name="nickName" value="https://www.cnblogs.com/xiaoqigui/p/kh96_spring_one"></property>
</bean>
</beans>
<bean>標簽:定義一個實體物件,會自動被創建 并 交給spring容器進行管理:
-
id 屬性:被spring容器進行管理的實體的 唯一標識,整個容器中,只能是唯一的(不可重復);
-
class屬性:指定創建當前實體物件的型別(全類名),spring底層是使用的 反射機制 ,根據指定的目標型別,創建目標實體(必須有 空參構造)
-
<property>子標簽:給當前創建物件的屬性值
- name:指定物件的屬性名
- value: 給屬性賦值
1.1.3 測驗
@Test
public void testSpringPrimer(){
//1.創建spring的核心容器物件(參考背景關系物件),決議spring的核心組態檔,將檔案中的bean標簽進行實體化(創建物件并賦值)
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//2. 寫法一: 從容器中獲取實體物件,根據核心組態檔中,配置的bean標簽的id屬性值
// 不足:強制轉化,容易出現轉換錯誤
User userOne = (User) context.getBean("userOne");
userOne.sayHello();
//對比以前創建物件的寫法(物件必須手動new創建,并手動賦值)
User userOld = new User();
userOld.setNickName("kh96_old");
userOld.sayHello();
}
1.1.4 總結
通過id屬性,獲取實體物件后需要強制轉換,容易出現強制轉化錯誤;
1.2 class 屬性
1.2.1 測驗
//寫法二:從容器中獲取實體物件,根據核心組態檔中,配置的bean標簽的class屬性指定的目標型別
User userTwo = context.getBean(User.class);
userTwo.sayHello();
1.2.2 總結
不足:如果存在同型別的多個實體,會報例外;
1.2.2.1 application.xml
當用多個同型別的實體:
...
<bean id="userOne" >
<property name="nickName" value="https://www.cnblogs.com/xiaoqigui/p/kh96_spring_one"></property>
</bean>
<!-- Configuration problem: Bean name 'userOne' is already used in this <beans> element -->
<bean id="userTwo" >
<property name="nickName" value="https://www.cnblogs.com/xiaoqigui/p/kh96_spring_two"></property>
</bean>
...
1.2.2.2 測驗
User userTwo = context.getBean(User.class);
會發生例外:
NoUniqueBeanDefinitionException: No qualifying bean of type 'com.kgc.spring.bean.User' available: expected single matching bean but found 2: userOne,userTwo
主要原因是由于只用class屬性去獲取實體,但是有多個相同型別的實體,所以無法確定你要獲取的是哪一個;
1.3 id 屬性 和 class 屬性 (推薦)
1.3.1 測驗
//寫法三:從容器中獲取實體物件,根據組態檔中,配置的bean標簽的id屬性值和class屬性指定的目標型別
User userTwoThree = context.getBean("userTwo", User.class);
1.3.2 總結
能夠確定唯一實體,推薦使用;
1.4 id 不能重復注意點
組態檔中的id必須是唯一的;
如果id不唯一:兩個id一樣的實體
...
<bean id="userOne" >
<property name="nickName" value="https://www.cnblogs.com/xiaoqigui/p/kh96_spring_one"></property>
</bean>
<bean id="userOne" >
<property name="nickName" value="https://www.cnblogs.com/xiaoqigui/p/kh96_spring_one"></property>
</bean>
...
報錯:
BeanDefinitionParsingException: Configuration problem: Bean name 'userOne' is already used in this <beans> element
提示 id 為 userOne 的實體已經存在;
1.5 實體化時機
當初始化spring的容器物件時,會將核心組態檔中所有的bean實體化,不是使用哪個,創建哪個;
2、DI
IOC(控制反轉是一種思想),DI是IOC的一種實作方式;
2.1 set 方式注入
2.1.1 物體
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
//用戶昵稱
//普通引數
private String nickName;
//私家車
//物體引數
private Car car;
//喜歡的書
//陣列引數
private String[] books;
//愛好
//list集合引數
private List<String> hobbies;
//喜歡的游戲
//set 集合
private Set<String> games;
//卡包
//map引數
private Map<String,String> cards;
//在校資訊
//properties引數
private Properties info;
//是否有女朋友 (主要是演示賦值為null,其他型別都可以)
//空引數注入
private Boolean wife;
}
2.1.2 引數 注入
...
<!-- 不同型別引數的set注入 -->
<bean id="user01" >
<!-- 1.普通引數 注入 -->
<property name="nickName" value="https://www.cnblogs.com/xiaoqigui/p/小氣鬼"></property>
<!-- 2.物體引數 注入 -->
<!-- 2.1 物體引數 注入方式一 外部引入 ref -->
<!-- <property name="car" ref="carOne"></property>-->
<property name="car">
<!-- 2.2 物體引數注入方式二 內部注入 <bean> -->
<bean >
<property name="brand" value="https://www.cnblogs.com/xiaoqigui/p/Bmw325"></property>
<property name="factory" value="https://www.cnblogs.com/xiaoqigui/p/華晨"></property>
<property name="price" value="https://www.cnblogs.com/xiaoqigui/p/300000"></property>
</bean>
</property>
<!-- 3.陣列引數 注入 -->
<property name="books">
<array>
<value>紅樓夢</value>
<value>水滸傳</value>
<value>三國演義</value>
<value>西游記</value>
</array>
</property>
<!-- 4.list集合引數 -->
<property name="hobbies" >
<list>
<value>跑步</value>
<value>尤克里里</value>
<value>敲代碼</value>
</list>
</property>
<!-- 5.set 集合引數 注入 -->
<property name="games">
<set>
<value>唱歌</value>
<value>跳舞</value>
<value>喝酒</value>
</set>
</property>
<!-- 6.map引數 -->
<property name="cards">
<map>
<entry key="身份證" value="https://www.cnblogs.com/xiaoqigui/p/1212121212121212"></entry>
<entry key="銀行卡" value="https://www.cnblogs.com/xiaoqigui/p/1111111111111111"></entry>
</map>
</property>
<!-- 7.properties引數 -->
<property name="info">
<props>
<prop key="學號">123456</prop>
<prop key="性別">男</prop>
<prop key="姓名">化羽</prop>
</props>
</property>
<!-- 8.空引數注入 -->
<property name="wife">
<null></null>
</property>
</bean>
<bean id="carOne" >
<property name="brand" value="https://www.cnblogs.com/xiaoqigui/p/Bmw325"></property>
<property name="factory" value="https://www.cnblogs.com/xiaoqigui/p/華晨"></property>
<property name="price" value="https://www.cnblogs.com/xiaoqigui/p/300000"></property>
</bean>
...
2.1.3 測驗
@Test
public void testPramsDI(){
User user01 = context.getBean("user01", User.class);
//輸入物件詳情
System.out.println(user01);
}
輸出結果:
User(
nickName=小氣鬼,
car=Car(brand=Bmw325, factory=華晨, price=300000.0),
books=[紅樓夢, 水滸傳, 三國演義, 西游記],
hobbies=[跑步, 尤克里里, 敲代碼],
games=[唱歌, 跳舞, 喝酒],
cards={身份證=1212121212121212, 銀行卡=1111111111111111},
info={學號=1913001072, 性別=男, 姓名=化羽},
wife=null
)
2.2 Constructor 構造器注入
2.2.1 按照默認順序 注入
2.2.1.1 引數注入
<!--
物體構造方法:Car(String brand, String factory, Double price)
-->
<!-- 構造器注入:通過構造方法,默認是按照構造方法的引數定義順序賦值 -->
<bean id="carTwo" >
<constructor-arg value="https://www.cnblogs.com/xiaoqigui/p/AudiA4"></constructor-arg>
<constructor-arg value="https://www.cnblogs.com/xiaoqigui/p/一汽"></constructor-arg>
<constructor-arg value="https://www.cnblogs.com/xiaoqigui/p/320000"></constructor-arg>
</bean>
2.2.1.2 測驗
@Test
public void testSpringDIConstructor(){
Car carTwo = context.getBean("carTwo", Car.class);
//輸出物件詳情
System.out.println(carTwo);
}
2.2.2 根據 引數的下標 和 型別 注入
2.2.2.1 引數注入
<!-- 根據構造器中引數的下標 和 型別 賦值 -->
<bean id="carThree" >
<constructor-arg index="0" value="https://www.cnblogs.com/xiaoqigui/p/BenzC200"></constructor-arg>
<constructor-arg index="1" value="https://www.cnblogs.com/xiaoqigui/p/北京"></constructor-arg>
<constructor-arg index="2" type="java.lang.Double" value="https://www.cnblogs.com/xiaoqigui/p/350000"></constructor-arg>
<!--
如果引數串列中,該型別的引數只用一個,也可以只指定引數型別
<constructor-arg type="java.lang.Double" value="https://www.cnblogs.com/xiaoqigui/p/350000"></constructor-arg>
-->
</bean>
2.2.2.2 測驗
@Test
public void testSpringDIConstructor2(){
Car carTwo = context.getBean("carThree", Car.class);
//輸入物件詳情
System.out.println(carTwo);
}
2.3 自定義 物體工廠bean
自定義物體工廠bean ,必須實作FactoryBean介面;
普通bean 與 工廠bean 的區別:
- 普通 bean:在組態檔中定義 bean 型別 就是 回傳型別
- 工廠 bean:在組態檔定義 bean 型別 和 回傳型別 不一樣
2.3.1 回傳bean
@Data
@ToString
public class Car {
/*
品牌
*/
private String brand;
/*
廠商
*/
private String factory;
/*
價格
*/
private Double price;
}
2.3.2 物體工廠 bean
- 在spring容器初始化時,創建當前工廠bean的實體物件,但是真實回傳的不是當前類的實體物件,而是當前類的實體物件回傳的目標實體物件(自定義);
- 作用:可以在程式中,實作自定義創建實體(還可以增加業務邏輯處理),放入容器;
- 存在的原因:spring框架對外開放了一個入口,可以讓其他的開發人員參與到spring底層創建bean的實體程序中去,給整合其他框架使用的,比如mybatis;
public class CarFactoryBean implements FactoryBean<Car> {
@Override
public Car getObject() throws Exception {
System.out.println("通過CarFactoryBean的實體物件的getObject方法:回傳一個自定義的car的實體");
return new Car("Byd唐","南京",2500000.0);
}
@Override
public Class<?> getObjectType() {
//指定給Object方法回傳的目標型別
return Class.class;
}
@Override
public boolean isSingleton() {
//是否單例
return false;
}
}
2.3.3 工廠bean容器中添加自定義實體物件
...
<!-- 使用工廠bean容器,添加自定義實體物件 -->
<bean id="carFactoryBean" ></bean>
...
2.3.4 測驗
@Test
public void testSpringFactoryBean(){
//從容器中獲取工廠bean的實體物件
Car car1 = context.getBean("carFactoryBean", Car.class);
Car car2 = context.getBean("carFactoryBean", Car.class);
//輸出物件詳情
System.out.println(car 1);
//在容器中添加的實體是 CarFactoryBean 型別,回傳的是
//Car(brand=Byd唐, factory=南京, price=2500000.0)
System.out.println("car1 == car2 : " + ( car1 == car2));
//false 說明工廠bean是多例的
}
3、scope作用域
- singleton 單例 (默認) 容器初始化之前創建;
- prototype 多例 (手動設定) 使用到的時候才創建;
3.1 singleton 單例
這里區別于,整個程式運行期間,有且只有唯一的實體(單例模式-懶漢和餓漢);
而容器中bean的單例,不是指當前類的實體在容器中,只有唯一的實體,而是當創建bean的實體時,此實體是單例(容器內唯一),但是同一個類的實體,容器中可以創建多個,每個都是單例的;
3.1.1 配置bean
<!-- scope="singleton" 不寫默認也是單例的 -->
<bean id="busTwo" scope="singleton">
<property name="brand" value="https://www.cnblogs.com/xiaoqigui/p/金龍2"></property>
<property name="factory" value="https://www.cnblogs.com/xiaoqigui/p/廈門2"></property>
<property name="price" value="https://www.cnblogs.com/xiaoqigui/p/1200000"></property>
</bean>
3.1.2 測驗
@Test
public void testScopeSingleton(){
//從容器中,獲取Bus的實體物件
Bus busThree = context.getBean("busTwo", Bus.class);
Bus busFour = context.getBean("busTwo", Bus.class);
System.out.println(busThree);
System.out.println(busFour);
System.out.println("singleton busThree == busFour:"+(busThree == busFour));
//true
}
3.2 prototype 多例
多例:prototype,不是spring容器中的默認作用,需要單獨指定;
spring容器創建時,不會自動創建指定作用域為多例的bean的實體,而是每次通過getBean方法,獲取bean的實體,才會創建bean的實體;
3.2.1 配置bean
<!-- scope="prototype" 多例需要手動設定 -->
<bean id="busThree" scope="prototype">
<property name="brand" value="https://www.cnblogs.com/xiaoqigui/p/中通3"></property>
<property name="factory" value="https://www.cnblogs.com/xiaoqigui/p/山東3"></property>
<property name="price" value="https://www.cnblogs.com/xiaoqigui/p/1200000"></property>
</bean>
3.2.2 測驗
@Test
public void testScopePrototype(){
Bus busOne = context.getBean("busThree", Bus.class);
Bus busTwo = context.getBean("busThree", Bus.class);
//輸入詳情
System.out.println(busOne);
System.out.println(busTwo);
System.out.println("prototype busOne == busTwo:"+(busOne == busTwo));
//false
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/502698.html
標籤:Java
上一篇:Java列舉簡單介紹
下一篇:day26--Java集合09
