學習Spring5必知必會(3)~Spring的核心 IoC 和 DI

一、Spring的核心 IoC(基於XML)

1、IoC容器

(1)BeanFactory容器創建對象:

	//使用BeanFactory
	@Test
	void testBeanFactory() throws Exception {
		Resource resource = new ClassPathResource("com/shan/container/container.xml");
		BeanFactory factory = new XmlBeanFactory(resource);
		Person person = factory.getBean("person", Person.class);	
	}

(2)BeanFactory的子介面 ApplicationContext容器創建對象:

	//使用ApplicationContext
	@Test
	void testApplicationContext() throws Exception {
		//習慣將上下文對象命名為ctx
		ApplicationContext ctx = new ClassPathXmlApplicationContext("com/shan/container/container.xml");
		Person person = ctx.getBean("person", Person.class);	
	}

(3)bean創建時機(ApplicationContext 和 BeanFactory 創建對象的區別 ):

  • BeanFactory 在創建Spring容器的時候,並不會立馬創建容器中管理的Bean對象,需要等到獲取某一個 bean 的時候才會創建該 bean–延遲初始化。(懶載入

  • ApplicationContext 在啟動 Spring 容器的時候就會創建所有的 bean(在 Web 應用使用Application

□ 當然可以通過屬性設置懶載入:

對於某個bean對象,在該bean元素上通過 屬性lazy-init 進行設置; 對所有bean對象,在beans上通過 屬性default-lazy-init進行設置。

2、bean實例化方式(4種):

★ ① 構造器實例化(bean 中有 無參數構造器),標準、常用

② 靜態工廠方法實例化:解決系統遺留問題。

③ 實例工廠方法實例化:解決系統遺留問題。

★ ④ 實現 FactoryBean 介面實例化:是第三種方式實例工廠的變種。 如集成 MyBatis 框架使用:org.mybatis.spring.SqlSessionFactoryBean

□ 方式2(工廠類中有一個創建bean對象的靜態方法):在xml的配置:

<bean id="" class="工廠類的全限定名" factory-method="工廠類中創建對象的靜態方法名"/>

□ 方式3(工廠類中有一個創建bean對象的方法):在xml的配置:

<bean id="factory3" class="工廠類的全限定名"/>
<bean id="create3" factory-bean="factory3" factory-method="工廠類中創建對象的方法名"/>

□ 方式4(實現 FactoryBean 介面實例化的方法):在xml的配置:(在方法3中,配置了兩個bean,咱的思路是:將其中一個bean “固定化”,

做法:將工廠實例化對象的方法規定為都叫 getObject 方法,因為咱定義的工廠類實現了FactoryBean介面(這是該介面的規範)

public class DogFactory implements FactoryBean<Dog>{
	@Override
	public Dog getObject() throws Exception {
		Dog dog = new Dog();
		return dog;
	}

	@Override
	public Class<?> getObjectType() {
		return Dog.class;
	}
}
<!-- 實現 FactoryBean 介面實例化:實例工廠變種, 如集成 MyBatis 框架使用 -->  
<bean id="dog" class="com.shan._04_factory_bean.DogFactory"/>
/* 使用spring的測試框架 */
@SpringJUnitConfig
public class App {	
	@Autowired
	private Person person;
	@Autowired
	private BeanFactory factory;
	@Autowired
	private ApplicationContext ctx;
	@Autowired
	private Dog dog;
	
	@Test
	void testBeanFactory() throws Exception {
		System.out.println(person);
		System.out.println(dog);

	}
}

3、bean作用域scope(常用單例)

  • 在 Spring 容器中是指其創建的 Bean 對象相對於其他 Bean 對象的請求可見範圍,定於語法格式:

    <bean id=”” class=”” scope=”作用域”/>
    • 單例和多例: singleton: 單例(默認的作用域) prototype: 多例

    • 在web應用中(request、session、application)

    • globalSession: 一般用於 Porlet 應用環境 , 分散式系統存在全局 session 概念(單點登錄)

    • websocket:將一個bean定義定義到WebSocket的生命周期

  • 預設情況下是單例 singleton

4、bean初始化和銷毀

  • 屬性init-method=”該類中初始化方法名” 和 屬性destroy-method=”該類中銷毀方法名”
  • 沒有使用spring的測試框架的話,就不能正常關閉IoC容器,即銷毀bean對象了(可以手動關閉)
<bean id="cat" class="com.shan.lifecycle.Cat" init-method="init" destroy-method="close"/>

■ bean 的生命周期:bean 從出生到消亡的整個過程。

BeanFactory:延遲初始化特點

ApplicationContext:在啟動Spring容器的時候,就會去創建bean對象

5、bean的生命周期

①執行Bean 構造器 ②為Bean注入屬性 ③調用Bean元素的init-method 進行初始化 ④獲取Bean對象,調用Bean對象的某個方法 ⑤調用Bean元素的destroy-method 進行銷毀對象 ⑥銷毀Spring容器

二、Spring的 DI

  • DI:Dependency Injection (依賴注入):Spring 創建對象的過程轉給你,將對象依賴的屬性(常量、對象、集合)通過配置設置值給該對象

  • IoC: 將對象的創建權,反轉給了Spring容器

■ 注入:☺ 簡單理解就是給對象設置值(通過對象的setter方法【屬性注入方法】、通過對象的構造器設置值【構造器注入方法】)

□ 設置值的類型:
  • 常量類型(固定不變),簡單類型 value
  • 對象類型(引用類型) ref
  • 集合類型 各自集合對應的元素

1、通過XML配置裝配

(1)XML自動裝配(不推薦)通過bean元素的屬性 autowire 自動裝配

✿(2)setter注入 [ 屬性注入(根據類型區分)]

■(常用) 注入常量 value

	<bean id="person" class="com.shan.di_setter.Person">
		<property name="name" value="shan"/>
		<property name="age" value="22"/>
		<property name="salary" value="10000"/>
	</bean>

■(常用) 注入對象 ref

    <bean id="cat" class="com.shan.di_setter2.Cat">
    	<property name="name" value="kity"/>
    </bean>    
	<bean id="person" class="com.shan.di_setter2.Person">
		<property name="name" value="shan"/>
		<property name="age" value="22"/>
		<property name="cat" ref="cat"/>
	</bean>

■ 注入集合

	<bean id="person" class="com.shan.di_setter3.Person">
		<!-- set類型 -->
		<property name="set">
			<set>
				<value>set1</value>
				<value>set2</value>
				<value>set3</value>
			</set>
		</property>
		<!-- list類型 -->
		<property name="list">
			<list>
				<value>list1</value>
				<value>list2</value>
			</list>
		</property>
		<!-- array類型 -->
		<property name="array">
			<array>
				<value>array1</value>
			</array>
		</property>
		<!-- map類型(字典類型) -->
		<property name="map">
			<map>
				<entry key="key1" value="value1"/>
			</map>
		</property>
		<!-- properties類型(特殊的map類型【key和value都是字元串】) -->
		<property name="prop">
			<value>
				p1=v1
				p2=v2
			</value>
		</property>
	</bean>

● 屬性的設置值是在 init 方法執行之前完成。com.shan.di_construstor

(3)構造器注入(跟屬性注入差不多,常用的是屬性注入,就是將property換成constructor-arg 元素)

   <!-- 構造器注入:常量類型 -->    
	<bean id="person" class="com.shan.di_construstor.Person">
		<constructor-arg name="name" value="shan"/>
		<constructor-arg name="age" value="18"/>
		<constructor-arg name="salary" value="10000"/>
	</bean>
	
	<!-- 構造器注入:對象類型 -->
	<bean id="cat" class="com.shan.di_construstor.Cat"/>
	<bean id="person2" class="com.shan.di_construstor.Person2">
		<constructor-arg name="c" ref="cat"/>
	</bean>

	<!-- 構造器注入:集合類型 -->

✿(4)bean元素繼承 (本質是xml配置內容的拷貝)

  • 通過abstract屬性進行抽取
  • 通過parent屬性進行引入

image

(5) 配置資料庫連接池

	<!-- 配置資料庫連接池 -->
	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
		<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
		<property name="url" value="jdbc:mysql://localhost:3306/springdemo?useSSL=false"/>
		<property name="username" value="root"/>
		<property name="password" value="admin"/>
		<property name="initialSize" value="2"/>
	</bean>

✿ 動態載入配置文件(db.properties—資料庫連接的配置資訊)

(6)property place holder

1)要是使用標籤Context,需要先引入Context的約束(在beans的基礎進行修改即可):

image

2) context:property-placeholder 屬性佔位符
     <!-- 從classpath的根路徑 載入db.properties -->   
     <context:property-placeholder location="classpath:db.properties"/>
3)使用 ${} 動態引入屬性值
	<!-- 配置資料庫連接池 -->
	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
		<property name="driverClassName" value="${jdbc.driverClassName}"/>
		<property name="url" value="${jdbc.url}"/>
		<property name="username" value="${jdbc.username}"/>
		<property name="password" value="${jdbc.password}"/>
		<property name="initialSize" value="${jdbc.initialSize}"/>
	</bean>