Spring的基本用法(大全-AOP)

Spring的AOP

面向切面編程(Aspect Orient Programming)分成兩類:

  • 靜態AOP實現:AOP框架在編譯階段對程序進行修改,即實現對目標類的增強,生成靜態的AOP代理類。以Aspect爲代表
  • 動態AOP實現:AOP框架在運行階段動態生成AOP代理,即實現對目標對象的增強。以Spring AOP爲代表 

AspectJ是基於Java語言的AOP框架。

  • 切面(Aspect):切面用於組織多個Advice,Advice放在切面中定義
  • 連接點(Joinpoint):程序執行過程中明確點,如方法的調用,或者異常的拋出。在Spring AOP中,連接點總是方法的調用
  • 增強處理(Advice):AOP框架在特定的切入點執行的增強處理。處理有“around”、“before”、“after”
  • 切入點(Pointcut):可以插入增強處理的連接點。當某個連接點滿足指定要求時,該連接點將被添加增強處理,該連接點也就變成切入點。連接點+增強處理==切入點。包含切入點表達式和名字、任意參數的方法的簽名。
    • AspectJ的切入點表達式:@Pointcut註解來標識
  • 引入:將方法或字段使用添加到被處理的類中。允許將新的接口引入到任何被處理的對象中去。
  • 目標對象:被AOP框架增強處理的對象。被增強的對象。AOP框架採用動態AOP實現,該對象是被代理對象。
  • 織入:將增強處理添加到目標對象中,並創建一個被增強的對象(AOP代理)的過程。

AOP代理就是AOP框架動態生成一個對象。該對象被作爲目標對象。AOP代理包含目標對象的全部方法。AOP方法在特定切入點添加了增強處理,回調目標對象的方法。

 

Spring僅支持將方法調用作爲連接點。如果需要對成員變量的訪問和更新作爲增強處理的連接點,考慮使用AspectJ。

 

  1. 定義普通業務組件
  2. 定義切入點,一個切入點可能橫切多個業務組件
  3. 定義增強處理,增強處理就是在AOP框架爲普通業務組件織入的處理動作。

AOP代理的方法 = 增強處理 + 目標對象的方法

零配置方式

@Aspect標識切面

@Pointcut標記切入點

 

不打算使用Spring的XMl Schema配置方式。

<!-- 啓動@AspectJ支持 -->
<bean class="org.springframeworking.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />
  1. 定義切面Bean。添加@Aspect註解爲切面類,不會對該bean類進行增強
  2. 定義增強處理。類型如下:

Before增強處理

在切面類中用@Before("excution()")修飾一個方法,需要指定value屬性值。該屬性值爲切入點表達式(如excution(org.aaa.bbb.*.*(..))。用於指定增強處理織入哪些切入點。

我的理解:用@Aspect修飾一個類爲切面類,在用@Before("excution(org.aaa.bbb.*.*(..))")修飾類中的方法,在bbb包下所有的類的方法作爲切入點(所有方法中的任意一個方法執行之前都要先調用一下用@before修飾的這個方法)

定義AfterReturning增強處理

目標方法完成後織入。

@AfterReturning註解的屬性:

   pointcut/value:指定對應的切入點表達式

returning:指定一個形參名。訪問目標方法的返回值,表示Advice可以定義與此相同的形參。限制目標方法返回指定類型的值或沒有返回值。

AfterThrowing增強處理

處理程序未處理的異常,@AfterThrowing的屬性如下

 pointcut/value:指定對應的切入點表達式

throwing:指定一個形參名。該形參可用於訪問目標方法拋出的異常。限制目標方法必須拋出指定類型的異常。

After增強處理

無論目標方法成功完成還是遇到異常終止,他都會被織入。所以After必須準備處理正常返回和異常返回兩種情況,常用於釋放資源。

@after("excution()")

Around增強處理

before增強處理+AfterReturning增強處理。不同的是它可以決定目標方法在什麼時候執行,是如何執行,甚至可以阻止目標方法的執行

既可以在目標方法執行之前織入,也可以在目標方法執行之後織入增強動作。

可以改變執行目標方法的參數值和返回值。

切入點表達式

切入點指示符有如下:

  • excution,屬性有modifiers-pattern(指定方法的修飾符)、ret-type-pattern(指定方法的返回值)等
  • within:用於限定匹配特定類型的連接點。Spring AOP使用時,只能匹配方法執行的連接點。
  • this:用於限定AOP代理的必須是指定類型的實例,匹配該對象的所有連接點。Spring AOP使用時,只能匹配方法執行的連接點。
  • target:限定目標對象必須是指定類型的實例。Spring AOP使用時,只能匹配方法執行的連接點。
  • args:用於對連接點的參數進行限制,要求參數是指定類型的實例。Spring AOP使用時,只能匹配方法執行的連接點。

XML配置文件方式

自動掃描Bean組件和切面類<context:component-scan base-package=" "><context:include-filter type=" " expression="" /></context:component-scan>

<aop:aspectj-autoproxy/>顯示啓動自動代理。要麼全部使用自動代理方式,要麼使用<aop:config/>

注意:所有的切面、切入點和增強處理都要包含在<aop:config/>元素內部。<beans/>元素下可以包含多個<aop:config/>。

1.配置切面

<aop:aspect>的屬性:

  • id:切面的標誌名
  • ref:將ref所引用的普通Bean轉換爲切面Bean
  • order:定義該切面Bean的優先級。與@AspectJ的@Order註解作用一樣

<aop:pointcut>的屬性:

id:切入點的標誌名

expression:切入點表達式

2.配置增強處理

<aop:before/>、<aop:after/>、<aop:afterreturning/>、<aop:afterthrowing/>、<aop:around/>

屬性:

pointcut:切入表達式

pointcut-ref:指定一個已存在的切入點名稱

method:指定方法名

throwing:指定形參名,<after-throwing/>有效

returning:指定形參名,<after-returning/>有效

Spring的事務

全局事務和局部事務

全局事務由應用服務器管理,需要JTA(Java Transaction API)支持

局部事務和底層採用持久化技術。採用JDBC持久化,需要使用Connection對象來操作事務;採用Hibernate持久化技術需要使用Session對象操作事務。

mybatis事務有兩種使用方式:

(a):使用JDBC的事務管理機制:即使用java.Sql.Connection對象完成對事務的提交,回滾和關閉操作。

(b):使用MANAGED的事務管理機制:mybatis本身不會去實現事務管理的相關操作,而是交個外部容器(JBOSS,WebLogic)來管理事務。當與spring整合使用後,一般使用spring來管理事務。

 

聲明式事務管理建立在AOP之上的。其本質是對方法前後進行攔截,然後在目標方法開始之前創建或者織入一個事務,在執行完目標方法之後根據執行情況提交或者回滾事務。聲明式事務最大的優點就是不需要通過編程的方式管理事務,這樣就不需要在業務邏輯代碼中摻雜事務管理的代碼,只需在配置文件中做相關的事務規則聲明(或通過基於@Transactional註解的方式),便可以將事務規則應用到業務邏輯中。

事務規則的屬性值:事務隔離、事務傳播、事務超時、只讀狀態。

事務傳播行爲

@Transactional所謂事務的傳播行爲是指,如果在開始當前事務之前,一個事務上下文已經存在,此時有若干選項可以指定一個事務性方法的執行行爲。在TransactionDefinition定義中包括瞭如下幾個表示傳播行爲的常量:

  • TransactionDefinition.PROPAGATION_REQUIRED:如果當前存在事務,則加入該事務;如果當前沒有事務,則創建一個新的事務。這是默認值。
  • TransactionDefinition.PROPAGATION_REQUIRES_NEW:創建一個新的事務,如果當前存在事務,則把當前事務掛起。
  • TransactionDefinition.PROPAGATION_SUPPORTS:如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續運行。
  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事務方式運行,如果當前存在事務,則把當前事務掛起。
  • TransactionDefinition.PROPAGATION_NEVER:以非事務方式運行,如果當前存在事務,則拋出異常。
  • TransactionDefinition.PROPAGATION_MANDATORY:如果當前存在事務,則加入該事務;如果當前沒有事務,則拋出異常。
  • TransactionDefinition.PROPAGATION_NESTED:如果當前存在事務,則創建一個事務作爲當前事務的嵌套事務來運行;如果當前沒有事務,則該取值等價於TransactionDefinition.PROPAGATION_REQUIRED。
屬性 類型 描述
value String 可選的限定描述符,指定使用的事務管理器
propagation enum: Propagation 可選的事務傳播行爲設置
isolation enum: Isolation 可選的事務隔離級別設置
readOnly boolean 讀寫或只讀事務,默認讀寫
timeout int (in seconds granularity) 事務超時時間設置
rollbackFor Class對象數組,必須繼承自Throwable 導致事務回滾的異常類數組
rollbackForClassName 類名數組,必須繼承自Throwable 導致事務回滾的異常類名字數組
noRollbackFor Class對象數組,必須繼承自Throwable 不會導致事務回滾的異常類數組
noRollbackForClassName 類名數組,必須繼承自Throwable 不會導致事務回滾的異常類名字數組

整合

啓動Spring

web.xml文件中配置創建Spring容器,讓Spring容器隨着Web應用的啓動而自動啓動,藉助ServletContextListener監聽器完成。實現ContextLoaderListener接口

 <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

 載入Spring的配置文件

<!--spring配置文件的位置-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>

在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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!-- 配置自動掃描的包 -->
    <context:component-scan base-package="com.qtu404">
        <!-- 掃描時跳過 @Controller 註解的JAVA類(控制器) -->
        <context:exclude-filter type="annotation"
                                expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <!-- 配置db.properyies文件位置 -->
    <bean id="configurer" class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer">
        <property name="locations" value="classpath:db.properties"></property>
    </bean>
    <!-- 配置數據源消息 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="${driver}"/>
        <property name="url" value="${url}"></property>
        <property name="username" value="${username}"></property>
        <property name="password" value="${password}"></property>
    </bean>
    <!-- 配置SqlSessionFactory -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="mapperLocations" value="classpath:com/qtu404/mapper/*.xml"></property>
    </bean>

    <!-- 配置事務管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 配置事務的傳播性 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="add*" propagation="REQUIRED"/>
            <tx:method name="delete*" propagation="REQUIRED"/>
            <tx:method name="update*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!-- 配置那些類的哪些方法需要參與事務 -->
    <aop:config>
        <aop:pointcut
                expression="execution(* com.qtu404.user.service.*.*(..))||execution(* com.qtu404.slide.service.*.*(..))"
                id="allMethod"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="allMethod"/>
    </aop:config>
</beans>

讓Spring管理控制器

SpringMVC和Spring整合的配置文件springmvc-servlet.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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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-4.1.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- scan the package and the sub package -->
    <context:component-scan base-package="com.qtu404"/>

    <!-- don't handle the static resource -->
    <mvc:default-servlet-handler/>

    <!-- if you use annotation you must configure following setting -->
    <mvc:annotation-driven/>
<!--文件上傳-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
          p:defaultEncoding="UTF-8">
    </bean>

    <bean id="logger" class="com.qtu404.common.aop.Logger"/>
    <aop:config>

        <!--用戶操作日誌-->
        <aop:aspect id="userLog" ref="logger">
            <aop:pointcut id="userPointcut"
                          expression="execution(* com.qtu404.user.controller.UserController.*(..))"/>
            <aop:after method="saveLog" pointcut-ref="userPointcut"/>
        </aop:aspect>

        <!--幻燈片操作日誌-->
        <aop:aspect id="slideLog" ref="logger">
            <aop:pointcut id="slidePointcut"
                          expression="execution(* com.qtu404.slide.controller.SlideController.*(..))"/>
            <aop:after method="saveLog" pointcut-ref="slidePointcut"/>
        </aop:aspect>

        <!--文件操作日誌-->
        <aop:aspect id="fileLog" ref="logger">
            <aop:pointcut id="filePointcut"
                          expression="execution(* com.qtu404.slide.controller.FileController.*(..))"/>
            <aop:after method="saveLog" pointcut-ref="filePointcut"/>
        </aop:aspect>

        <!--文件夾作日誌-->
        <aop:aspect id="folderLog" ref="logger">
            <aop:pointcut id="folderPointcut"
                          expression="execution(* com.qtu404.folder.controller.FolderController.*(..))"/>
            <aop:after method="saveLog" pointcut-ref="folderPointcut"/>
        </aop:aspect>
    </aop:config>

    <!-- configure the InternalResourceViewResolver -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          id="internalResourceViewResolver">
        <!-- 前綴 -->
        <property name="prefix" value="/"/>
        <!-- 後綴 -->
        <property name="suffix" value=".html"/>
    </bean>
</beans>

 

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