- spring框架
1. Spring是分層的Java SE/EE應用 full-stack輕量級開源框架
以IoC(Inverse Of Control:反轉控制)和AOP(Aspect Oriented Programming:面向切面編程)爲內核
提供了展現層Spring MVC和持久層Spring JDBC以及業務層事務管理等衆多的企業級應用技術
還能整合開源世界衆多著名的第三方框架和類庫,逐漸成爲使用最多的Java EE企業應用開源框架
2. Spring優勢:
a. 方便解耦,簡化開發:
降低程序之間的依賴
應該做到編譯期不依賴,運行期才依賴
例如:
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName("com.mysql.jdbc.Driver");
b. AOP編程的支持
c. 聲明式事務的支持
d. 方便程序測試
e. 方便集成各種框架
f. 降低JavaEE API使用難度
g. Java源碼是經典的學習範例
3. 程序的耦合:
a. 程序間的依賴關係:程序的編譯依賴於其他的程序
1. 類之間的依賴
2. 方法之間的依賴
b. 解耦思想:
1. 使用反射來創建對象,而避免使用new關鍵字
2. 通過讀取配置文件來獲取要創建的對象的全限定類名
c. 開發中應用:
1. 創建工廠類來生產Bean對象:
Bean在計算機英語中表示可重用組件
2. JavaBean:
JavaBean指用Java語言編寫的可重用組件
JavaBean範圍遠大於實體類
3. 需要一個配置文件來配置需要生產的Bean對象
配置內容:唯一標識=全限定類名(key=value)
4. 通過讀取配置文件配置的內容,反射創建對象
配置文件可以使用xml或properties文件
Object obj = Class.forName(beanPath).newInstance();
* 每次調用newInstance方法都會調用一次默認構造函數
* 此時創建的對象形式爲多例的
5. 工廠類的構建:
* 創建一個靜態私有的Properties對象用於加載配置文件
* 創建一個靜態容器Map對象用於保存配置文件中要求的對象
* 在static靜態代碼塊中讀取配置文件,利用反射創建對象,將配置文件中的key和新創建的對象存儲Map容器
* 在靜態方法中返回Map容器中早已創建好的對象
* 由於靜態代碼塊僅在類加載時執行一次,因此該工廠調用成員方法創建的對象都是同一個,對象爲單例形式
6. 使用工廠生產Bean對象先決條件:
業務層和持久層中幾乎可以改變的成員變量
- IoC控制:Inverse Of Control 反轉控制
1. 原始創建對象形式:
由app尋找資源,然後創建對象(new形式)
2. 控制反轉創建形式:
由app向工廠索要對象,工廠控制資源(工廠類形式)
將原本自主創建對象的權力交予工廠,即控制反轉。包括依賴注入和依賴查找
- 使用spring的IOC解決程序耦合
1. 下載解壓spring framework:
spring-framework-5.0.2.RELEASE-dist
2. 導入相關spring相關jar包:
spring-aop-5.0.2.RELEASE.jar -- 基於註解開發的必備jar包
spring-beans-5.0.2.RELEASE.jar -- 中間4個爲核心容器的jar包
spring-context-5.0.2.RELEASE.jar
spring-core-5.0.2.RELEASE.jar
spring-expressoin-5.0.2.RELEASE.jar
spring-jcl-5.0.2.RELEASE.jar -- 集成了apache的日誌組件做成了自己的jar包
使用座標定位時僅需要定位spring-context即可:
* 當前工程依賴於spring-context
* spring-context依賴於spring-beans,spring-aop,spring-expression,spring-core
* spring-aop依賴於spring-beans,spring-core
* spring-beans依賴於spring-core
* spring-expression依賴於spring-core
* spring-core依賴於spring-jcl
3. 創建xml配置文件,並導入約束:
/resource/bean.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">
<!--配置相關信息-->
</beans>
4. 使用bean標籤將對象的創建交給框架:
<bean id="唯一標識key" class="需要創建的對象的全限定類名"></bean>
5. 獲取spring核心容器,並根據id獲取創建的對象:
ApplicationContext coreObj = new ClassPathXmlApplicationContext("配置文件名(bean.xml)")
E element = (E) coreObj.getBean("唯一標識id");
* 獲取核心容器的三種形式:
1. ClassPathXmlApplicationContext:僅能加載類路徑下的配置文件
2. FileSystemXmlApplicationContext:可以加載任意磁盤路徑下的配置文件(需要有訪問權限)
3. AnnotationConfigApplicationContext:用於讀取註解創建容器
* 核心容器的兩個接口:
1. ApplicationContext:單例對象適用,但是可以根據配置設置立即或延遲,因此開發更爲常用
在構建核心容器時,創建對象爲立即加載方式。即,讀取完配置文件後,立即創建所有配置中的對象
2. BeanFactory:多例對象適用
在構建核心容器時,創建對象爲延遲加載方式。即,僅由id獲取對象時創建該對象
6. spring對Bean的管理細節:
a. 創建bean的三種方式:
1. 使用默認構造函數創建對象:
在spring的配置文件中使用bean標籤,配置id和class屬性,且沒有其他屬性和標籤,調用默認構造函數創建
<bean id="唯一標識key" class="需要創建的對象的全限定類名"></bean>
如果此時類中沒有默認構造函數(重寫了帶參構造函數但是沒有重寫默認構造函數),則不能創建bean對象
2. 使用其他類中的方法創建對象:
在spring的配置文件中使用bean標籤,配置id,factory-bean,factory-method屬性,調用工廠類中方法創建
<bean id="唯一標識key" class="創建對象的工廠的全限定類名"></bean>
<bean id="唯一標識key" factory-bean="工廠唯一標識id" factor-method="創建對象的方法"></bean>
3. 使用其他類中的靜態方法創建對象:
在spring的配置文件中使用bean標籤,配置id,class,factory-method屬性,調用工廠類中靜態方法創建
<bean id="唯一標識key" class="工廠全限定類名" factor-method="創建對象的靜態方法"></bean>
b. bean對象的作用範圍:
1. 默認情況下,bean標籤創建對象的形式是單例的
2. 通過bean標籤的scope屬性來指定bean的作用範圍:
* singleton:單例的(默認值)
* prototype:多例的
* request:作用於web應用的請求範圍
* session:作用於web應用的會話範圍
* global-session:作用於集羣環境的會話範圍(全局會話範圍),當不是集羣範圍時,等同於session範圍
c. bean對象的生命週期:
1. 單例對象:
生命週期與容器相同:容器創建時創建,容器銷燬時銷燬
調用ClassPathXmlApplicationContext的close方法銷燬容器
2. 多例對象:
生命週期:使用對象時spring框架創建,當對象長時間沒有使用且無其他對象引用時有java垃圾回收機制回收
7. spring中的依賴注入:
a. 依賴關係管理:
表示層調用業務層,業務層調用持久層這是必然會出現的
於是將調用間的對象創建交由spring,這種依賴關係有spring管理
我們只需要在配置文件中說明,在當前類中需要使用其他類的對象,其他類的對象有spring提供
依賴關係的維護稱爲:依賴注入
b. 能夠注入的數據:
1. 基本類型和String
2. 其他bean類型(在配置文件中或者註解配置過的bean)
3. 複雜類型/集合類型
c. 注入方式:
1. 使用構造函數
被注入的類中重寫了帶參構造函數時,在bean標籤的配置內部加入constructor-arg標籤
<bean id="唯一標識key" class="需要創建的對象的全限定類名">
<constructor-arg></constructor-arg>
<!--
constructor-arg標籤中的屬性:
* type:用於指定要注入的數據的數據類型,該數據類型也是構造函數中某個或某些參數的類型
* index:用於指定注入數據在構造函數中參數的索引,從0開始
* name:用於指定注入數據在構造函數中的名稱 (常用形式)
=======================以上3個屬性用於確定給構造函數中哪個參數賦值==================
* value:指定參數注入的值,僅限基本類型和String類型
* ref:用於引用關聯的bean對象,僅限IOC容器中配置過的對象
-->
</bean>
例如:
當需要注入的參數爲Date類型數據時,並不能直接使用value賦值一個字符串
而需要另外定義一個bean對象,反射創建一個Date對象,用constructor-arg的ref屬性引用創建的Date對象
<bean id="now" class="java.util.Date"></bean>
<bean id="xxx" class="xxx.xxx.xxx">
<constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>
優勢:
由於沒有默認構造函數,所以創建對象時,配置注入參數的操作是必須的,否則無法創建對象
劣勢:
改變了bean對象的實例化方式,如果不使用該bean對象也同樣需要配置參數注入
2. 使用set方法
被注入的類中必須含有參數的set方法,可以不寫get方法。在bean標籤內部使用property標籤
<bean id="唯一標識key" class="需要創建的對象的全限定類名">
<property></property>
<!--
property標籤中的屬性:
* name:用於指定注入數據在set方法中的屬性名稱
* value:指定參數注入的值,僅限基本類型和String類型
* ref:用於引用關聯的bean對象,僅限IOC容器中配置過的對象
-->
</bean>
優劣與構造方法創建相反
複雜數據類型注入:
* 給List結構的參數注入:
在property內部有子標籤list,set,array,在通過子標籤的子標籤<value></value>進行元素賦值
<property name="myList">
<list>
<value>索引爲0的值</value>
<value>索引爲1的值</value>
...
</list>
</property>
* 用於給map結構的參數注入:
在property內部有子標籤map,propos,在通過子標籤的key和value爲元素賦鍵值
<property name="myMap">
<map key="鍵" value="值"></map>
</property>
* 相同結構的注入操作標籤可以互換,即List可以使用set/list/array標籤都行
3. 使用註解
- 舉例:使用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">
<!-- 配置Service -->
<bean id="accountService" class="cn.mysilent.service.impl.AccountServiceImpl">
<!-- 注入dao -->
<property name="accountDao" ref="accountDao"></property>
</bean>
<!--配置Dao對象-->
<bean id="accountDao" class="cn.mysilent.dao.impl.AccountDaoImpl">
<!-- 注入QueryRunner -->
<property name="runner" ref="runner"></property>
</bean>
<!--配置QueryRunner,爲了使每個查詢不相互干擾,配置該對象的創建爲多例prototype-->
<!--如果QueryRunner是單例對象,則面臨多個dao使用時,可能引發線程安全問題-->
<bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
<!--注入數據源-->
<constructor-arg name="ds" ref="dataSource"></constructor-arg>
</bean>
<!-- 配置數據源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!--連接數據庫的必備信息-->
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
<property name="user" value="用戶名"></property>
<property name="password" value="密碼"></property>
</bean>
</beans>