Spring IOC 基礎整理

IOC(控制反轉):從組件的角度來說
DI(依賴注入):從容器的角度說

Bean加載:

ApplicationContext 默認支持預加載(就是spring在創建容器的時候,就會自動創建的singleton bean ,並立即根據property調用setter方法),可在bean元素上使用lazy-int="true"關閉,或beans上使用default-lazy-int="true"關閉內所有bean

// 從類路徑下搜索配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("");
// 從絕對路徑或相對路徑下去搜索配置文件
ApplicationContext context = new FileSystemXmlApplicationContext("");
<bean id="student" class="com.lwy.beans.Student">
	<constructor-arg value="張三" type="java.lang.String"></constructor-arg>
	<constructor-arg ref="book" type="com.lwy.Book"></constructor-arg>
	<property name="age" value="20"></property>
</bean>

國際化:

<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
	<property name="basenames">
		<list><!-- 用list代表數組 -->
			<value>mess</value>
		</list>
	</property>
</bean>

資源訪問

Resource resource = context.getResource("https://www.baidu.com");

使用Resource類:類路徑(classpath:)、磁盤(file:///)、網絡(http://、ftp://)

獲取Spring容器——setter方法調用後調用setApplicationContext

public class XXXBean implements ApplicationContextAware {
	private ApplicationContext context;

	@Override
	public void setApplicationContext(ApplicationContext ctx) throws BeansException {
		// TODO Auto-generated method stub
		this.context = ctx;
	}

}

Bean作用域:

scope設置屬性

-singleton:默認,性能好,單例。在整個Spring容器生命中,該Bean都是同一個,容器創建>容器銷燬。

-prototype:程序調用getBean創建>GC回收時銷燬♻️

-request:只能在Web應用中使用,相當於一次請求內是singleton行爲。

-session:只能在Web應用中使用,相當於一次用戶會話(session)內是singleton行爲。

-global session:只能在Porlet應用中使用。

配置簡化 p: c:

xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
<bean id="student" class="com.lwy.beans.Student" p:age="18" c:_0="張三" c:_1-ref="book"></bean>

自動裝配:autowire

-no:不使用自動裝配,默認值。

-byName:根據setter方法名來自動裝配。Spring查找容器中全部Bean,找出其中id屬性與setter方法名去掉set前綴後同名的Bean來完成注入。如果沒有找到匹配的Bean實例,則Spring不會進行任何注入,也不報錯。

-byType:根據setter方法的形參類型來自動裝配。BeanFactory查找容器中全部Bean,如果正好有一個Bean類型與setter形參類型匹配,就自動注入這個Bean。如果有多個這樣的Bean,就拋出一個異常;如果沒有找到匹配的Bean實例,則Spring不會進行任何注入,也不報錯。autowire-candidate="false"放棄自動注入。

-constructor:與byType類似,區別是用於構造注入的參數,如果BeanFactory中不是恰好一個Bean與構造器參數類型相同,則會拋出一個異常。

-autodetect:BeanFactory根據Bean內部結構,決定使用constructor或byType。如果找到一個默認的構造函數,那麼就會應用byType。

集合注入

<!-- String[] strings -->
<property name="strings">
	<!-- 用List構建數組 -->
	<list>
		<value>stringvalue1</value>
		<value>stringvalue2</value>
	</list>
</property>

<!-- List<Bean> list -->
<property name="list">
	<!-- 用List構建List -->
	<list>
		<ref bean="bean1" />
		<ref bean="bean2" />
	</list>
</property>

<!-- Set<String> set -->
<property name="set">
	<!-- 用Set構建set -->
	<set>
		<value>stringvalue1</value>
		<value>stringvalue2</value>
	</set>
</property>

<!-- Map<String,Bean> map -->
<property name="map">
	<!-- 用map、entry構建map -->
	<map>
		<entry key="string1" value-ref="bean1"></entry>
		<entry key="string2" value-ref="bean2"></entry>
	</map>
</property>

<!-- 給Properties屬性集合配置 -->
<property name="properties">
	<!-- 用props、prop構建properties -->
	<props>
		<prop key="propertie1">string1</prop>
		<prop key="propertie2">string2</prop>
	</props>
</property>

工廠配置

  • 調用工廠類的靜態工廠方法

factory-method指定工廠方法的名字。

class:指定工廠類的類名

使用<constructor-arg></constructor-arg>傳參。

  • 調用實例工廠的實例工廠方法。

factory-method指定工廠方法的名字。

factory-bean:指定工廠類的對象。

使用<constructor-arg></constructor-arg>傳參。

 

抽象Bean和子Bean

項目中,可能有多個Bean的部分配置信息是完全相同的。於是考慮:將這些通用信息提取出來,配置一個Bean模板,但我們不希望Spring創建該Bean,於是需要指定abstract="true"

抽象Bean並不抽象類,只是一個配置信息的模板,需要指定ID。

子Bean通過parent=""屬性獲取模板配置信息。

 

FactoryBean

它是Spring提供的一個特殊接口。FactoryBean接口是工廠Bean的標準接口,實現該接口的Bean通常作爲工廠Bean使用,當我們把工廠Bean部署在容器中、並通過getBean()方法來獲取時,容器返回的不是FactoryBean實例,而是返回FactoryBean的產品(也就是該工廠Bean的getObject方法的返回值)。

如果需要獲取工廠Bean本身,並能不直接請求Bean id,而在Bean id前增加&符號。

FactoryBean有三個方法需要實現。

public class FieldFactoryBean implements FactoryBean<Object> {

	private String targetClass;
	private String targetField;
	
	public String getTargetClass() {
		return targetClass;
	}
	
	public void setTargetClass(String targetClass) {
		this.targetClass = targetClass;
	}
	
	public String getTargetField() {
		return targetField;
	}
	
	public void setTargetField(String targetField) {
		this.targetField = targetField;
	}

	// 負責返回工廠的產品
	@Override
	public Object getObject() throws Exception {
		// TODO Auto-generated method stub
		Class clazz = Class.forName(targetClass);
		Field field = clazz.getField(targetField);
		return field.get(null);
	}

	// 多餘的,返回值類型
	@Override
	public Class<?> getObjectType() {
		// TODO Auto-generated method stub
		return Object.class;
	}

	// 返回產品是否爲單例
	@Override
	public boolean isSingleton() {
		// TODO Auto-generated method stub
		return false;
	}

}

spring會檢測容器中所有的Bean,如果發現該Bean的類實現了FactoryBean接口(工廠),代碼就變了

Object factory = new XxxFactoryBean();

factory.setXxx(); setter幾次取決你配置中有幾行property

<bean id="getFieldTemplate" abstract="true"
class="com.lwy.beans.FieldFactoryBean"></bean>
<bean id="classField" parent="getFieldTemplate"
p:targetClass="java.sql.Connection"
p:targetField="TRANSACTION_SERIALIZABLE"></bean>

獲取Bean的id

讓Bean實現BeanNameAware

實現該接口中setBeanName(String arg0)方法 其中arg0爲配置id

 

Bean的生命週期

Spring容器中得Bean主要有singleton(性能較好,爲默認)和prototype(不存在生命週期概念)

Singleton:

  • 出生之後,爲他配置各種資源。

①使用init-method=""來指定方法名;②實現InitializingBean接口的public void afterPropertiesSet() throws Exception初始化方法,優先級更高

  • 銷燬之前:釋放資源。

①使用destroy-method=""來指定方法名;②實現DisposableBean接口的public void destroy() throws Exception方法。

爲了讓容器合理的銷燬

對Java SE項目,需要爲容器註冊一個關閉鉤子;

AbstractApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

context.registerShutdownHook();

對於Java Web項目,項目關閉時候容器會銷燬。

作用域不同步

永遠不要配置singleton依賴於Prototype Bean。

解決方法:抽象類設置<lookup-method name="" bean=""/>

告訴Spring用CGLLB動態生成一個子類(Javassist:比CGLIB性能更好)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章