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" init-method="initTruck" destroy-method="destroyTruck">
<property name="brand" value="https://www.cnblogs.com/xiaoqigui/p/江淮"></property>
<property name="factory" value="https://www.cnblogs.com/xiaoqigui/p/安徽"></property>
<property name="price" value="https://www.cnblogs.com/xiaoqigui/p/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 ></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" >
<property name="brand" value="https://www.cnblogs.com/xiaoqigui/p/Bnw520"></property>
<property name="factory" value="https://www.cnblogs.com/xiaoqigui/p/華晨"></property>
<property name="price" value="https://www.cnblogs.com/xiaoqigui/p/450000"></property>
</bean>
<!-- 容器中實體化一個容器的House物件 -->
<bean id="house" >
<property name="type" value="https://www.cnblogs.com/xiaoqigui/p/三室一廳"></property>
<property name="area" value="https://www.cnblogs.com/xiaoqigui/p/96"></property>
<property name="price" value="https://www.cnblogs.com/xiaoqigui/p/2800000"></property>
</bean>
<!-- 根據型別自動裝配 -->
<bean id="person" autowire="byType">
<property name="nickName" value="https://www.cnblogs.com/xiaoqigui/p/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" >
<property name="brand" value="https://www.cnblogs.com/xiaoqigui/p/Bnw520"></property>
<property name="factory" value="https://www.cnblogs.com/xiaoqigui/p/華晨"></property>
<property name="price" value="https://www.cnblogs.com/xiaoqigui/p/450000"></property>
</bean>
<bean id="carNew" >
<property name="brand" value="https://www.cnblogs.com/xiaoqigui/p/AudiA6"></property>
<property name="factory" value="https://www.cnblogs.com/xiaoqigui/p/一汽"></property>
<property name="price" value="https://www.cnblogs.com/xiaoqigui/p/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" autowire="byName">
<property name="nickName" value="https://www.cnblogs.com/xiaoqigui/p/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="分層注解標識類的類名首字母小寫" > ... <bean>
3.1.2 自定義id 屬性
如果不想使用默認的類名首字母小寫,我們可以使用注解的value屬性執行一個自定義的id值;
比如:@Service(value="https://www.cnblogs.com/xiaoqigui/p/自定義的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 = "https://www.cnblogs.com/xiaoqigui/p/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>
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/502960.html
標籤:Java
上一篇:第5章 回圈和運算式
