Spring(二)-生命週期 + 自動裝配(xml) +自動裝配(註解)
1、生命週期
**Spring容器的 bean **的生命週期;
1.1 預設生命週期
1.1.1 生命週期
- 呼叫構造方法,建立例項物件;
- set方法,給例項物件賦值;
- init 初始化方法 初始化物件;(手寫並配置到bean上init-method="")
- 使用容器中的bean物件;
- destroy 銷燬方法 銷燬物件 (手寫並配置到bean上destroy-method="")
1.1.2 bean 實體類
Truck
@Data @ToString public class Truck { //品牌 private String brand; //廠商 private String factory; //價格 private Double price; public Truck() { //空參構造方法,觀察bean什麼時候例項化 System.out.println("------ 1.呼叫構造方法,建立例項物件 ------\n"); } public void setBrand(String brand) { //任意一個set方法,觀察bean什麼時候注入引數 System.out.println("------ 2.set方法,給例項物件賦值 ------"); this.brand = brand; } public void initTruck(){ //init初始化方法,觀察bean什麼時候初始化 //需要再配置bean的時候,配置init初始化方法 System.out.println("------ 3.Truck init 初始化方法 初始化物件 ------\n"); this.brand = "大運"; } public void destroyTruck(){ //destory方法,觀察bean什麼時候銷燬 //需要再配置bean的時候,配置destory銷燬方法 System.out.println("------ 5.Truck destroy 銷燬方法 銷燬物件 ------\n"); } //這裡方法上標註的序號是測試後得來的; }
1.1.3 bean 配置
spring-lifecycle.xml
<!-- spring容器中bean的生命週期 預設生命週期 --> <bean id="truck" class="com.kgc.spring.lifecycle.Truck" init-method="initTruck" destroy-method="destroyTruck"> <property name="brand" value="江淮"></property> <property name="factory" value="安徽"></property> <property name="price" value="200000"></property> </bean>
1.1.4 測試
public class TestSpringLifeCycle { //定義全域性容器物件,如果需要關閉容器物件, //必須使用ApplicationContext的子介面 ConfigurableApplicationContext //ApplicationContext介面主要各種屬性的get方法; //ConfigurableApplicationContext重在對各種屬性的配置; // private ApplicationContext context; private ConfigurableApplicationContext context; @Before public void initApplicationContext(){ context = new ClassPathXmlApplicationContext("spring-lifecycle.xml"); } //測試spring 容器的bean的生命週期,預設和加了處理器兩種場景 @Test public void testSpringBeanLifeCycle(){ //從容器中,獲取Truck的是例項物件 Truck truck = context.getBean("truck", Truck.class); //使用物件 System.out.println("------ 4.使用容器中的bean物件"+truck +" ------"); //關閉容器 context.close(); } }
輸出結果:
//可以得出 spring中bean的 預設生命週期 ------ 1.呼叫構造方法,建立例項物件 ------ ------ 2.set方法,給例項物件賦值 ------ ------ 3.Truck init 初始化方法 初始化物件 ------ ------ 4.使用容器中的bean物件Truck(brand=大運, factory=安徽, price=200000.0) ------ ------ 5.Truck destroy 銷燬方法 銷燬物件 ------
1.1.5 ApplicationContext 和 ConfigurableApplicationContext
參考部落格: ApplicationContext和ConfigurableApplicationContext解析
-
ApplicationContext介面主要 各種 屬性的get方法 ;
-
ConfigurableApplicationContext重在對 各種 屬性的配置 ;
1.2 增加後置處理器
1.2.1 生命週期
1.呼叫構造方法,建立例項物件;
2.set方法,給例項物件賦值;
3-1.後置處理的 before 方法;
3.初始化方法 初始化物件;
3+1.後置處理器的的 after 方法;
4.使用容器中的bean物件;
5.destroy 銷燬方法 銷燬物件;
1.2.2 後置處理器
-
要求:必須實現 BeanPostProcessor 介面
-
自定義 bean 的 後置處理器,對容器中 所有的bean統一處理(生效) ,
-
要生效的話,必須將此處理器放到容器中( 配置到spring的核心配置檔案中 ,增加處理器的例項配置);
注意:
當前案例, 只對
容器中的 一個例項處理
;
MyBeanPostProcessor
public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { //在容器中bean的例項物件呼叫 初始化方法 前 自動呼叫(init方法可以沒有,不影響) //模擬處理容器中的bean,接下來的寫法,僅限於當前的用法案例(容器中就 只有一個 卡車例項) Truck truck = (Truck)bean; System.out.println("++++++ 容器中的卡車物件 "+truck+"++++++"); System.out.println("++++++ 3-1,後置處理的 before 方法 ++++++"); truck.setBrand("後置處理的before方法"); System.out.println("++++++ 處理後的 卡車物件 "+truck+" ++++++\n"); return truck; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { //bean 初始化方法 執行 後,呼叫此方法處理bean Truck truck = (Truck)bean; System.out.println("++++++ 初始化容器中的卡車物件 "+truck+"++++++"); System.out.println("++++++ 3+1,後置處理器的的 after 方法 ++++++"); truck.setBrand("after"); System.out.println("++++++ 初始化後 處理後的 卡車物件 "+truck+" ++++++\n"); return truck; } }
1.2.3 bean 配置
在配置檔案中配置 MyBeanPostProcessor;
<!-- 配置後置處理器的例項,自動放入容器中,可以自動生效 (容器中所有的例項生效) --> <bean class="com.kgc.spring.lifecycle.MyBeanPostProcessor"></bean>
1.2.4 測試
跟預設生命週期的測試程式碼一致;
輸出結果:
------ 1.呼叫構造方法,建立例項物件 ------ ------ 2.set方法,給例項物件賦值 ------ ++++++ 容器中的卡車物件 Truck(brand=江淮, factory=安徽, price=200000.0)++++++ ++++++ 3-1,後置處理的 before 方法 ++++++ ------ 2.set方法,給例項物件賦值 ------ ++++++ 處理後的 卡車物件 Truck(brand=後置處理的before方法, factory=安徽, price=200000.0) ++++++ ------ 3.Truck init 初始化方法 初始化物件 ------ ++++++ 初始化容器中的卡車物件 Truck(brand=大運, factory=安徽, price=200000.0)++++++ ++++++ 3+1,後置處理器的的 after 方法 ++++++ ------ 2.set方法,給例項物件賦值 ------ ++++++ 初始化後 處理後的 卡車物件 Truck(brand=after, factory=安徽, price=200000.0) ++++++ ------ 4.使用容器中的bean物件Truck(brand=after, factory=安徽, ------ 5.Truck destroy 銷燬方法 銷燬物件 ------
1.2.3 BeanPostProcesso
參考部落格: BeanPostProcessor簡介
BeanPostProcessor官方定義為工廠鉤子,我們也俗稱 後置處理器 。它 允許自定義修改新的bean例項 ,例如檢查標記介面或用代理包裝它們。應用程式上下文可以在其bean定義中自動檢測BeanPostProcessor bean,並將它們應用於隨後建立的任何bean。
BeanPostProcessor 的 前置處理 和 後置處理 ;
 +自動裝配(註解).assets/image-20220826150821502.png)
2、自動裝配(xml)
2.1 bean 實體類
Person
@Data public class Person { //暱稱 private String nickName; //車子 private Car car; //房子 private House house; }
Car
@Data public class Car { //品牌 private String brand; //廠商 private String factory; //價格 private Double price; }
House
@Data public class House { //戶型 private String type; //面積 private double area; //價格 private Integer price; }
2.2 bean 配置 (byType)
autowire="byType":根據 屬性 的 型別 自動裝配;
spring-auto.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的自動裝配方式,基於xml配置檔案方式,掌握 --> <!-- 容器中例項化一個容器的Car物件 --> <bean id="car" class="com.kgc.spring.auto.Car"> <property name="brand" value="Bnw520"></property> <property name="factory" value="華晨"></property> <property name="price" value="450000"></property> </bean> <!-- 容器中例項化一個容器的House物件 --> <bean id="house" class="com.kgc.spring.auto.House"> <property name="type" value="三室一廳"></property> <property name="area" value="96"></property> <property name="price" value="2800000"></property> </bean> <!-- 根據型別自動裝配 --> <bean id="person" class="com.kgc.spring.auto.Person" autowire="byType"> <property name="nickName" value="huayu"></property> </bean> </beans>
2.3 測試
public class TestSpringAutoUserXml { private ApplicationContext context; @Before public void initApplicationContext(){ context = new ClassPathXmlApplicationContext("spring-auto.xml"); } @Test public void testSpringAuto(){ Person person = context.getBean("person", Person.class); //使用物件 System.out.println("容器中的person物件:"+person); } }
輸出結果:
容器中的person物件:Person( nickName=huayu, car=Car(brand=Bnw520, factory=華晨, price=450000.0), house=House(type=三室一廳, area=96.0, price=2800000) )
2.4 bean 配置 (多個同類型bean)
bean 配置:
其他不變,多增加一個Car型別的例項bean;
<bean id="car" class="com.kgc.spring.auto.Car"> <property name="brand" value="Bnw520"></property> <property name="factory" value="華晨"></property> <property name="price" value="450000"></property> </bean> <bean id="carNew" class="com.kgc.spring.auto.Car"> <property name="brand" value="AudiA6"></property> <property name="factory" value="一汽"></property> <property name="price" value="450000"></property> </bean>
測試,報錯資訊:
No qualifying bean of type 'com.kgc.spring.auto.Car' available: expected single matching bean but found 2: car,carNew
總結
:autowire="byType" 當有 多個相同型別的bean時
, 無法確定
要裝配的 bean;
2.5 bean 配置(byName)
其他配置資訊不變,設定 autowire="byName" ,根據 屬性 的 名字 自動裝配;
<bean id="person" class="com.kgc.spring.auto.Person" autowire="byName"> <property name="nickName" value="hauyu"></property> </bean>
測試輸出結果:
容器中的person物件:Person( nickName=huayu, car=Car(brand=Bnw520, factory=華晨, price=450000.0), house=House(type=三室一廳, area=96.0, price=2800000) )
總結
:
-
byType:根據型別自動裝配:
- 根據實體屬性的 型別 ,到容器中,根據 bean型別 進行唯一匹配,如果可以匹配到對應型別的bean的例項,就會執行自動裝配, 如果不能唯一匹配(同類型的bean有多個),會報錯;
-
byName: 根據名稱自動裝配:
- 根據 屬性 的 屬性名 ,到容器中,根據 bean的id 屬性值,進行唯一匹配,如果能夠成功匹配,執行自動裝配, 如果匹配不到,不執行自動裝配,實體屬性為null;
3、自動裝配 (註解)
3.1 註解
- @Component 普通元件註解;
- @Repository 持久層註解
- @Service 業務層註解
- @Controller 控制層註解
3.3.1 註解的原理
預設情況下:spring自動將分層元件(@Controller,@Service,@Repository,@component) 標識的類 (不是介面), 自動建立例項物件放入容器 中,使用bean的標識 id值為 對應 類名首字母小寫 就相當於,幫我們手動添加了配置 :
<bean id="分層註解標識類的類名首字母小寫" class="分層註解標識類的全類名"> ... <bean>
3.1.2 自定義id 屬性
如果 不想使用預設的類名首字母小寫 ,我們可以使用註解的value屬性執行一個自定義的id值 ;
比如:@Service(value="自定義的id值"),註解只有value屬性,可以省略value執行,簡化為@Service("自定義的id值")
3.1.3 分層元件的目的
分層元件的目的,就僅僅是為了 方便開發人員 明確當前註解 所在的類所對應的角色 ,在使用上, 建議使用 ,按照官方定義的使用,防止模糊不清; 在springMVC框架中@Controller有特殊含義;
3.2 配置檔案
spring建立容器物件時,如果解析到 component-scan 元件掃描配置,會將base-package指定的基包(父包)及其子包所有增加了分層元件的類,自動建立例項,放進容器中;
配置檔案
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd "> <!-- 元件掃描:註解標識的元件,必須通過元件掃描配置,才可以新增到spring的容器中--> <context:component-scan base-package="com.kgc.spring.acnocation" > </context:component-scan> </beans>
3.3 預設id屬性 測試
3.3.1 實體
@Component public class User { //使用者名稱 @Value("huayu") //@Value() 自動裝配引數 private String userName; //使用者密碼 @Value("123") private String userPwd; }
3.3.2 測試
@Test public void testSpringAutoUserAnnotation(){ User user = context.getBean("user", User.class); System.out.println(user); //User(userName=huayu, userPwd=123) }
3.4 自定義id屬性 測試
3.4.1 實體(自定義id屬性)
@Component(value = "myUser") public class User { //使用者名稱 private String userName; //使用者密碼 private String userPwd; }
3.4.2 測試
@Test public void testSpringAutoUserAnnotation(){ //User user = context.getBean("user", User.class); //自定義id後,預設id不能使用: No bean named 'user' available //必須使用自定義id User user = context.getBean("myUser", User.class); System.out.println(user); //User(userName=huayu, userPwd=123) }
3.5 自動裝配
3.5.1 @Autowired
- 元件自動裝配,可以實現 實體屬性型別的自動裝配 ,自動到spring的容器中,根據當前 屬性的型別或者名稱進行注入 ,如果容器中 能匹配到 ,就 直接 將例項物件 注入到當前實體屬性上 ,無序手動指定;
-
@Autowired自動裝配原理:首先會根據byType方式,進行自動裝配,
- 如果 不能唯一匹配 (存在同類型多個例項物件),會再次 嘗試使用byName方式 ,根據當前實體屬性名,到容器中進行匹配(容器中bean的id值),如果能唯一匹配,直接執行自動裝配,
-
預設情況下,@Autowired註解標識的實體屬性,必須被裝配
- 如果 裝配失敗 ,就直接 丟擲異常;
- 如果 不需要校驗必須被裝配 (專案啟動,如果裝配失敗,專案是起不來);
- 通過指定 required = false ,去除必須執行自動裝配的校驗(即便容器中找不到裝配的例項,也不會丟擲異常);
- 如果自動裝配,容器中 存在多個同類型的bean物件 ,可以使用註解@Qualifier("容器中同類型多個bean的某個id值"), 實現指定到容器中,找對應的bean例項物件 ,進行自動裝配;
- 底層是如何做的:在指定要掃描的包時,<context:component-scan> 元素會 自動註冊一個bean的後置處理器 :AutowiredAnnotationBeanPostProcessor的例項。該後置處理器可以 自動裝配標記了@Autowired、@Resource或@Inject註解的屬性 。
3.5.2 實體
People
@Data @Component("myPeople") public class People { //暱稱 @Value("huayu") private String name; //玩具 @Autowired private Toy toy; }
Toy介面
public interface Toy { //得到玩具 public void getToy(); }
ToyImpl1
@Component("toy1") public class ToyImpl1 implements Toy { @Value("玩具車") private String toyName; @Override public void getToy() { System.out.println(this.toyName); } }
3.5.3 測試
注意
:可以 通過介面型別獲取實現類
(推薦使用);
@Test public void testAutowired (){ People people = context.getBean("myPeople", People.class); people.getToy().getToy(); //玩具車 }
3.5.4 存在多個相同型別的bean
當存在 多個相同型別的bean , 不能唯一匹配 ,會 自動裝配錯誤 ;
在寫一個Toy實現類,ToyImpl2
@Component("toy2") public class ToyImpl2 implements Toy { @Value("尤克里裡") private String toyName; @Override public void getToy() { System.out.println(this.toyName); } }
3.5.4.1 測試
報錯資訊(專案無法啟動):
No qualifying bean of type 'com.kgc.spring.acnocation.bean.Toy' available: expected single matching bean but found 2: toy1,toy2
主要資訊:型別無法唯一匹配;
3.5.4.2 required = false 允許不裝配
People
@Data @Component("myPeople") public class People { //暱稱 @Value("huayu") private String name; //玩具 @Autowired (required = false) private Toy toy; }
專案可以啟動但是還是報錯(一般專案中不會有兩個相同型別的實現類;)
3.5.4.3 @Quailfy
People
@Data @Component("myPeople") public class People { //暱稱 @Value("huayu") private String name; //玩具 @Autowired @Qualifier("toy2") //指定bean的id值 private Toy toy; }
3.5.4.4 測試
@Test public void testAutowired (){ People people = context.getBean("myPeople", People.class); System.out.println(people.getToy()); //com.kgc.spring.acnocation.bean.ToyImpl2@15d9bc04 people.getToy().getToy(); //尤克里裡 }
3.6 指定掃描 排除掃描
3.6.1 指定掃描
include-filter
指定掃描(包含掃描):
- 只會掃描指定的 類 或者 某類元件 (使用分組掃描), 加入 到容器中;
- 但是 必須配合 父標籤的 user-default-filter 使用,預設值是true,就是全部掃描;
- 指定掃描,如果要生效 必須改為false ;
- 指定掃描 某類元件 ,type="annotation" expression="某類元件註解的全類名";
- 指定掃描 某個類 ,type="assignable" expression="某個類的全類名";
3.6.1.1 指定掃描某類元件
type="annotation"
- org.springframework.stereotype.Component
- org.springframework.stereotype.Repository
- org.springframework.stereotype.Service
- org.springframework.stereotype.Controller
<!-- 指定掃描 @Component 元件 --> <context:component-scan base-package="com.kgc.spring.acnocation" use-default-filters="false" > <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/> </context:component-scan>
3.6.1.2 指定掃描某個類
type="assignable"
<!-- 指定掃描 ToyImpl1 --> <context:component-scan base-package="com.kgc.spring.acnocation" use-default-filters="false" > <context:include-filter type="assignable" expression="com.kgc.spring.acnocation.bean.ToyImpl1"/> </context:component-scan>
3.6.2 排除掃描
exclude-filter
- 排除掃描(剔除掃描):排除指定的 類 或 某類元件 , 不加入 到容器中,處理排除外的其他元件,仍然會被新增到容器中;
- 不需要配合父標籤,use-default-filters="true" 因為,預設就是在全部掃描的基礎上剔除;
- 排除掃描 某類元件 ,type="annotation" expression="某類元件註解的全類名";
- 排除掃描 某個類 ,type="assignable" expression="某個類的全類名";
3.6.2.1 排除掃描某類元件
type="annotation"
<!-- use-default-filters="true" 可寫可不寫 --> <!-- 排除掃描 @Component元件 --> <context:component-scan base-package="com.kgc.spring.acnocation" use-default-filters="true" > <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"/> </context:component-scan>
3.6.2.2 排除掃描個類
type="assignable"
<!-- 排除掃描 ToyImpl1 --> <context:component-scan base-package="com.kgc.spring.acnocation" > <context:exclude-filter type="assignable" expression="com.kgc.spring.acnocation.bean.ToyImpl1"/> </context:component-scan>
- 執行緒池底層原理詳解與原始碼分析
- 30分鐘掌握 Webpack
- 線性迴歸大結局(嶺(Ridge)、 Lasso迴歸原理、公式推導),你想要的這裡都有
- 【前端必會】webpack loader 到底是什麼
- 中心化決議管理——雲端分析
- HashMap底層原理及jdk1.8原始碼解讀
- 詳解JS中 call 方法的實現
- 列印 Logger 日誌時,需不需要再封裝一下工具類?
- 初識設計模式 - 代理模式
- 密碼學奇妙之旅、01 CFB密文反饋模式、AES標準、Golang程式碼
- Springboot之 Mybatis 多資料來源實現
- CAS核心思想、底層實現
- 面試突擊86:SpringBoot 事務不回滾?怎麼解決?
- 基於electron vue element構建專案模板之【打包篇】
- MiniWord .NET Word模板引擎,藉由Word模板和資料簡單、快速生成檔案。
- 認識執行緒,初始併發
- 1-VSCode搭建GD32開發環境
- 初識設計模式 - 原型模式
- 執行緒安全問題的產生條件、解決方式
- 2>&1到底是什麼意思?