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性能更好)