Spring框架詳解

1、Spring框架

概述:spring框架可以解決對象創建以及對象之間依賴關係的一中框架。

常用專業術語:

  • 組建/框架設計:
侵入式設計:引入了框架後對現有的結構產生影響,即需要繼承或實現某些特定類。例如:struts框架

非侵入式設計:引入了框架對現有的結構無影響。例如:hibernate、spring框架。

  • 控制反轉(inversion on control----IOC)
控制反轉(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

                   指定當前的方法必須在事務的環境下執行;

                   如果當前運行的方法,已經存在事務:  事務會掛起; 會始終開啓一個新的事務,執行完後;  剛纔掛起的事務才繼續運行。
























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