-
課程主要內容
- 理解IOC
- 基於XML的注入
- Bean的作用域
- 單例問題
- 循環引用問題
目錄
Spring是一個對象管理容器,自動化完成了創建、初始化、銷燬等工作。
傳統的方式
Person person = new Person();
person.setAge(18);
person.setName("zhangsan");
IoC概念
IoC是一個概念,是一種思想,其實現方式多種多樣。當前比較流行的實現方式之一是DI。
基於XML的DI
ApplicationContext.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">
XML文件結構
- <beans beans是xml文件的根節點
- xmlns=http://www.springframework.org/schema/beans xmlns=xml NameSpace 類似於java中的package
- xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xsi是指xml文件遵守xml規範,xsi全名:xml schema instance
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> 是指具體用到的schema資源
真的去網上找xsd文件?
當然不是
spring在加載xsd文件時總是先試圖在本地查找xsd文件(spring的jar包中已經包含了所有版本的xsd文件),如果沒有找到,纔會轉向去URL指定的路徑下載
驗證PluggableSchemaResolver.class中
=後面是包名以及具體xsd文件位置
多配置文件
ApplicationContext加載多文件
new ClassPathXmlApplicationContext("applicationContext.xml","application-service.xml");
引入外部文件
<import resource="application-service.xml"/>
Bean的定義與註冊
Spring的配置文件是用於指導Spring工廠進行Bean的生產、依賴關係注入及Bean實例分發的“圖紙”,它是一個或多個標準的XML文檔
<bean id="food" class="com.msb.Food"></bean>
一個bean只能有一個id,但是可以有多個name作爲別名
Alias 別名
<alias name="user" alias="my_user_bean" />
spring ioc container
spring ioc container 管理一個或多個bean,bean來自xml中對bean定義的元數據(configuration metadata)
元數據信息
Class |
類 |
Name,id |
標識 |
Scope |
作用域 |
Constructor arguments |
構造器注入 |
Properties |
屬性注入 |
autowiring mode |
自動裝配 |
lazy-initialization mode |
懶加載 |
initialization method |
初始化 |
destruction method |
銷燬 |
構造器注入 constructor-arg
Person的構造器
public Person(String name, Integer age, Food food) {
super();
this.name = name;
this.age = age;
this.food = food;
}
Xml
指定name
<bean id="person" class="com.msb.Person">
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="name" value="zhangsan"></constructor-arg>
</bean>
指定類型
<constructor-arg type="int" value="7500000"/>
指定index
<constructor-arg index="0" value="7500000"/>
屬性注入
<bean id="person" class="com.msb.Person">
<property name="age" value="19"></property>
<property name="name" value="zhangsan"></property>
</bean>
使用p-namespace
屬性注入
添加一個namespace
xmlns:p=http://www.springframework.org/schema/p
使用 p
<bean id="person" class="com.msb.Person" p:age="21" p:name = "zhangsan">
<bean id="person" class="com.msb.Person" p:age="21" p:name = "zhangsan" p:food-ref="food">
使用c- namespace
構造器注入
<bean id="foo" class="x.y.Foo" c:bar-ref="bar" c:baz-ref="baz" c:email= "foo@bar.com"/>
使用java.util.Properties
在set方法中把properties
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
this.name=properties.getProperty("name");
}
對其他Bean的引用
<property name="food" ref="food"></property>
<bean id="food" class="com.msb.Food"></bean>
集合
Properties
private Properties adminEmails;
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.org</prop>
<prop key="support">support@example.org</prop>
<prop key="development">development@example.org</prop>
</props>
</property>
List
private List someList;
<property name="someList">
<list>
<value>apple</value>
<value>orange</value>
</list>
</property>
Map
private Map someMap;
<property name="someMap">
<map>
<entry key="an entry" value="just some string"/>
<entry key ="a ref" value-ref="food"/>
</map>
</property>
depends-on 提前初始化
可以使某個bean在創建前,先創建別的bean
lazy-init
在容器啓動後,bean被使用到的時候才加載。可以使用的lazy-init屬性
bean id="person" class="com.msb.Person" lazy-init="false"
作用域
spring爲bean提供了6種作用域,其中4種只有在web-aware的ApplicationContext種纔有用。用戶也可以創建自定義的作用域。
singleton 、prototype 、websocket、request、session、application、websocket
singleton scope 單例作用域
每一個類,在一個容器內只能產生一個實例
prototype scope 原型作用域
該bean每次被注入,或者使用getBean()方法獲取時,都返回一個新的實例。
Request scope
該作用域的bean,在每個HTTP request都會新建一個實例,當一個request結束後,該實例也會被丟棄。
Session scope
某一個用戶在一段時間內,會使用同一個session,session有超時時間,過了超時時間則session失效。不同用戶使用不同的session。
Application scope
該作用域的bean,每一個application會創建一個
MVC下Spring的單例
想在一個singleton內多次調用短存活時間的bean(propotype、request、session等),希望調用的是不同的實例,那麼就需要使用AOP proxy技術
線程安全問題
業務對象並沒有做線程的併發限制,因此不會出現各個線程之間的等待問題,或是死鎖問題
MVC中的實體bean不是單例的
成員變量
在併發訪問的時候這些成員變量將會是併發線程中的共享對象,也是影響線程安全的重要因素
引用類型的成員
其中引用類型的成員變量即我們在controller中注入的service,在service中注入的dao,這裏將其定義爲成員變量主
要是爲了實例化進而調用裏面的業務方法,在這些類中一般不會有全局變量,因此只要我們的業務方法不含有獨立的
全局變量即使是被多線程共享,也是線程安全的。
Controller service dao 層中的業務類是多線程共享的,但是每個線程在處理數據的時候具體處理的數據是在每個線程中各自有一份。
controller層
- final類型 線程安全
- 成員變量 有狀態數據有線程安全問題
循環依賴的bean
構造器注入循環依賴
當循環依賴的bean都是通過構造器注入依賴的時候,無論這些bean是singleton還是prototype,在獲取bean的時候都會失敗。
通過屬性注入
- 循環依賴的bean都是singleton 成功
- 循環依賴的bean都是prototype 失敗
- 同時有singleton和prototype 當先獲取的那個bean是singleton時,就會成功,否則失敗
當Spring容器在創建A時,會發現其引用了B,從而會先去創建B。同樣的,創建B時,會先去創建C,而創建C時,又先去創建A。最後A、B、C之間互相等待,誰都沒法創建成功