1、Spring框架
概述:spring框架可以解決對象創建以及對象之間依賴關係的一中框架。
常用專業術語:
- 組建/框架設計:
非侵入式設計:引入了框架對現有的結構無影響。例如:hibernate、spring框架。
- 控制反轉(inversion on control----IOC)
依賴注入(DI):處理對象的依賴關係
區別:
控制反轉解決對象的創建問題。而依賴注入是在對象創建成功後解決對象的關係的處理。
- AOP面向切面編程
2、Spring IOC容器(applicationContext.xml)
IOC容器是spring核心,作用:創建對象和處理對象的依賴關係
默認的applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>
</beans>
2.1 對象創建的細節
a、什麼時候創建
scope="prototype"(默認值) 在用到對象的時候才創建-------------多例(action對象)
scope="singleton" 在啓動(容器初始化之前),就已經創建了對象,整個web應用只有一個-------------------單例(dao、service、工具類)
b、是否延遲創建
lazy-init="false"(默認值) 不延遲創建,即在啓動的時候就創建。
lazy-init="true" 延遲初始化,在用到對象的時候才創建。
2.2 創建對象的幾種方式
a、調用無參構造器
b、帶參構造器
c、工廠類創建:靜態/動態
<!-- ###############對象創建############### -->
<!-- 1. 默認無參數構造器
<bean id="user1" class="cn.User"></bean>
-->
<!-- 2. 帶參數構造器 -->
<bean id="user2" class="cn.User">
<constructor-arg index="0" type="int" value="100"></constructor-arg>
<constructor-arg index="1" type="java.lang.String" value="Jack"></constructor-arg>
</bean>
<!-- 定義一個字符串,值是"Jack" ; String s = new String("jack")-->
<bean id="str" class="java.lang.String">
<constructor-arg value="Jacks"></constructor-arg>
</bean>
<bean id="user3" class="cn.User">
<constructor-arg index="0" type="int" value="100"></constructor-arg>
<constructor-arg index="1" type="java.lang.String" ref="str"></constructor-arg>
</bean>
<!-- 3. 工廠類創建對象 -->
<!-- # 3.1 工廠類,實例方法 -->
<!-- 先創建工廠 -->
<bean id="factory" class="cn.ObjectFactory"></bean>
<!-- 在創建user對象,用factory方的實例方法 -->
<bean id="user4" factory-bean="factory" factory-method="getInstance"></bean>
<!-- # 3.2 工廠類: 靜態方法 -->
<!--
class 指定的就是工廠類型
factory-method 一定是工廠裏面的“靜態方法”
-->
<bean id="user" class="cn.ObjectFactory" factory-method="getStaticInstance"></bean>
2.3 對象依賴關係
spring中常用的幾種注入方式
a、通過構造器
b、通過set方法給屬性注入值(最常用)
*****************************
需要給set方法。
*****************************
<!-- dao instance -->
<bean id="userDao" class="cn.dao.UserDao"></bean>
<!-- service instance -->
<bean id="userService" class="cn.service.UserService">
<property name="userDao" ref="userDao"></property>
</bean>
<!-- action instance -->
<bean id="userAction" class="cn.action.UserAction">
<property name="userService" ref="userService"></property>
</bean>
c、p名稱空間
<span style="white-space:pre"> </span><bean id="userDao" class="cn.dao.UserDao"></bean>
<bean id="userService" class="cn.service.UserService" p:userDao-ref="userDao"></bean>
<bean id="userAction" class="cn.action.UserAction" p:userService-ref="userService"></bean>
<p align="left"><span style="color:teal;"><span style="white-space:pre"> </span><</span><span style="color: rgb(63, 127, 127);">bean</span> <span style="color: rgb(127, 0, 127);">id</span>=<em><span style="color:#2A00FF;">"user"</span></em><span style="color: rgb(127, 0, 127);">class</span>=<em><span style="color:#2A00FF;">"cn.entity.User"</span></em> <span style="color: rgb(127, 0, 127);">p:name</span>=<em><span style="color:#2A00FF;">"Jack0001"</span></em><span style="color: teal;">></</span><span style="color: rgb(63, 127, 127);">bean</span><span style="color: teal;">></span></p>
d、註解
註解方式可以簡化spring的IOC容器的配置。。但不利於後期的維護。
使用步驟:
1)先引入context名稱空間
xmlns:context="http://www.springframework.org/schema/context"
2)開啓註解掃描
<context:component-scanbase-package="包"></context:component-scan>
3)使用註解
通過註解的方式,把對象加入ioc容器。 創建對象以及處理對象依賴關係,相關的註解:
@Component 指定把一個對象加入IOC容器
@Repository 作用同@Component; 在持久層使用
@Service 作用同@Component; 在業務邏輯層使用
@Controller 作用同@Component; 在控制層使用
@Resource 屬性注入
3、AOP編程
3.1 概述:
aop(aspectobject programming 面向切面編程)功能:讓關注點代碼和業務代碼分離
關注點:重複代碼
切面:關注點形成的類就叫切面類。
面向切面編程就是對重複代碼進行抽取,在業務執行的時候再動態植入。
切入點:
可以通過切入點表達式攔截指定的類的指定方法,在類或方法執行的時候動態植入切面類代碼。
3.2 註解方式實現AOP編程
步驟
1) 先引入aop相關jar文件 (aspectj aop優秀組件)
spring-aop-3.2.5.RELEASE.jar 【spring3.2源碼】
aopalliance.jar 【spring2.5源碼/lib/aopalliance】
aspectjweaver.jar 【spring2.5源碼/lib/aspectj】或【aspectj-1.8.2\lib】
aspectjrt.jar 【spring2.5源碼/lib/aspectj】或【aspectj-1.8.2\lib】
注意:用到spring2.5版本的jar文件,如果用jdk1.7可能會有問題。
需要升級aspectj組件,即使用aspectj-1.8.2版本中提供jar文件提供。
2) bean.xml中引入aop名稱空間
3) 開啓aop註解
4) 使用註解
@Aspect 指定一個類爲切面類
@Pointcut("execution(* cn.itcast.e_aop_anno.*.*(..))") 指定切入點表達式
@Before("pointCut_()") 前置通知: 目標方法之前執行
@After("pointCut_()") 後置通知:目標方法之後執行(始終執行)
@AfterReturning("pointCut_()") 返回後通知: 執行方法結束前執行(異常不執行)
@AfterThrowing("pointCut_()") 異常通知: 出現異常時候執行
@Around("pointCut_()") 環繞通知: 環繞目標方法執行
3.3 XML實現AOP編程
Xml實現aop編程:
1) 引入jar文件 【aop 相關jar, 4個】
2) 引入aop名稱空間
3)aop 配置
*配置切面類 (重複執行代碼形成的類)
*aop配置: 攔截哪些方法 / 攔截到方法後應用通知代碼
<!-- dao 實例 -->
<bean id="userDao" class="cn.dao.UserDao"></bean>
<bean id="orderDao" class="cn.dao.OrderDao"></bean>
<!-- 切面類 -->
<bean id="aop" class="cn.aop.Aop"></bean>
<!-- Aop配置 -->
<aop:config>
<!-- 定義一個切入點表達式: 攔截哪些方法 -->
<aop:pointcut expression="execution(* cn.*.*.*(..))" id="pt"/>
<!-- 切面 -->
<aop:aspect ref="aop">
<!-- 環繞通知 -->
<aop:around method="around" pointcut-ref="pt"/>
<!-- 前置通知: 在目標方法調用前執行 -->
<aop:before method="begin" pointcut-ref="pt"/>
<!-- 後置通知: -->
<aop:after method="after" pointcut-ref="pt"/>
<!-- 返回後通知 -->
<aop:after-returning method="afterReturning" pointcut-ref="pt"/>
<!-- 異常通知 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
3.4 切入點表達式
切入點表達式: 可以對指定的“方法”進行攔截; 從而給指定的方法所在的類生層代理對象。
<aop:config>
<!-- 定義一個切入點表達式: 攔截哪些方法 -->
<!--<aop:pointcut expression="execution(* cn.*.*(..))" id="pt"/>-->
<!-- 【攔截所有public方法】 -->
<!--<aop:pointcut expression="execution(public * *(..))" id="pt"/>-->
<!-- 【攔截所有save開頭的方法 】 -->
<!--<aop:pointcut expression="execution(* save*(..))" id="pt"/>-->
<!-- 【攔截指定類的指定方法, 攔截時候一定要定位到方法】 -->
<!--<aop:pointcut expression="execution(public * cn.g_pointcut.OrderDao.save(..))" id="pt"/>-->
<!-- 【攔截指定類的所有方法】 -->
<!--<aop:pointcut expression="execution(* cn.g_pointcut.UserDao.*(..))" id="pt"/>-->
<!-- 【攔截指定包,以及其自包下所有類的所有方法】 -->
<!--<aop:pointcut expression="execution(* cn..*.*(..))" id="pt"/>-->
<!-- 【多個表達式】 -->
<!--<aop:pointcut expression="execution(* cn.g_pointcut.UserDao.save()) || execution(* cn.g_pointcut.OrderDao.save())" id="pt"/>-->
<!--<aop:pointcut expression="execution(* cn.g_pointcut.UserDao.save()) or execution(* cn..g_pointcut.OrderDao.save())" id="pt"/>-->
<!-- 下面2個且關係的,沒有意義 -->
<!--<aop:pointcut expression="execution(* cn.g_pointcut.UserDao.save()) && execution(* cn.g_pointcut.OrderDao.save())" id="pt"/>-->
<!--<aop:pointcut expression="execution(* cn.g_pointcut.UserDao.save()) and execution(* cn.g_pointcut.OrderDao.save())" id="pt"/>-->
<!-- 【取非值】 -->
<!--<aop:pointcut expression="!execution(* cn.g_pointcut.OrderDao.save())" id="pt"/>-->
<aop:pointcut expression=" not execution(* cn.g_pointcut.OrderDao.save())" id="pt"/>
<!-- 切面 -->
<aop:aspect ref="aop">
<!-- 環繞通知 -->
<aop:around method="around" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
4、事務
事務是一組操作的執行單元,相對於數據庫操作來講,事務管理的是一組SQL指令,比如增加,修改,刪除等,事務的一致性,要求,這個事務內的操作必須全部執
行成功,如果在此過程種出現了差錯,比如有一條SQL語句沒有執行成功,那麼這一組操作都將全部回滾
事務特性(ACID)
•Atomic(原子性):要麼都成功,要麼都失敗
•Consistent(一致性):數據應該不被破壞
•Isolate(隔離性):用戶間操作不相混淆
•Durable(持久性):永久保存
4.1 事務控制概述
編程式事務控制
自己手動控制事務,就叫做編程式事務控制。
Jdbc代碼: Conn.setAutoCommite(false); // 設置手動控制事務
Hibernate代碼: Session.beginTransaction(); // 開啓一個事務
【細粒度的事務控制:可以對指定的方法、指定的方法的某幾行添加事務控制】
(比較靈活,但開發起來比較繁瑣:每次都要開啓、提交、回滾.)
聲明式事務控制
Spring提供了對事務的管理, 這個就叫聲明式事務管理。
Spring提供了對事務控制的實現。用戶如果想用Spring的聲明式事務管理,只需要在配置文件中配置即可;不想使用時直接移除配置。這個
實現了對事務控制的最大程度的解耦。
Spring聲明式事務管理,核心實現就是基於Aop。
【粗粒度的事務控制:只能給整個方法應用事務,不可以對方法的某幾行應用事務。】
(因爲aop攔截的是方法。)
Spring聲明式事務管理器類:
Jdbc技術:DataSourceTransactionManager
Hibernate技術:HibernateTransactionManager
4.2 聲明式事務管理
步驟:
1) 引入spring-aop相關的4個jar文件
2) 引入aop名稱空間 【XML配置方式需要引入】
3) 引入tx名稱空間 【事務方式必須引入】
xml實現:
<!-- 數據源對象: C3P0連接池 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass"value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl"value="jdbc:mysql:///hib_demo"></property> <property name="user"value="root"></property> <property name="password"value="root"></property> <property name="initialPoolSize"value="3"></property> <property name="maxPoolSize"value="10"></property> <property name="maxStatements"value="100"></property> <property name="acquireIncrement"value="2"></property> </bean> <span style="white-space:pre"> </span><!-- 配置事務管理器類 --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置事務增強(如果管理事務?) --> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="get*" read-only="true"/> <tx:method name="find*" read-only="true"/> <tx:method name="*" read-only="false"/> </tx:attributes> </tx:advice> <!-- Aop配置: 攔截哪些方法(切入點表表達式) + 應用上面的事務增強配置 --> <aop:config> <aop:pointcut expression="execution(* cn.itcast.a_tx.DeptService.*())" id="pt"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/> </aop:config>
註解方式實現:
使用註解實現Spring的聲明式事務管理,更加簡單!
步驟:
1) 必須引入Aop相關的jar文件
2) bean.xml中指定註解方式實現聲明式事務管理以及應用的事務管理器類
3)在需要添加事務控制的地方,寫上: @Transactional
@Transactional註解:
1)應用事務的註解
2)定義到方法上: 當前方法應用spring的聲明式事務
3)定義到類上: 當前類的所有的方法都應用Spring聲明式事務管理;
4)定義到父類上: 當執行父類的方法時候應用事務。
<!-- 數據源對象: C3P0連接池 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql:///hib_demo"></property> <property name="user" value="root"></property> <property name="password" value="root"></property> <property name="initialPoolSize" value="3"></property> <property name="maxPoolSize" value="10"></property> <property name="maxStatements" value="100"></property> <property name="acquireIncrement" value="2"></property> </bean> <!-- 事務管理器類 --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 開啓註解掃描 --> <context:component-scan base-package="包"></context:component-scan> <!-- 註解方式實現事務: 指定註解方式實現事務 --> <tx:annotation-driven transaction-manager="txManager"/>
事務屬性:
@Transactional( readOnly = false, // 讀寫事務 timeout = -1, // 事務的超時時間不限制 noRollbackFor = ArithmeticException.class, // 遇到數學異常不回滾 isolation = Isolation.DEFAULT, // 事務的隔離級別,數據庫的默認 propagation = Propagation.REQUIRED // 事務的傳播行爲 ) public void save(Dept dept){ deptDao.save(dept); int i = 1/0; deptDao.save(dept); }
事務傳播行爲:
Propagation.REQUIRED
指定當前的方法必須在事務的環境下執行;
如果當前運行的方法,已經存在事務, 就會加入當前的事務;
Propagation.REQUIRED_NEW
指定當前的方法必須在事務的環境下執行;
如果當前運行的方法,已經存在事務: 事務會掛起; 會始終開啓一個新的事務,執行完後; 剛纔掛起的事務才繼續運行。