Spring AOP學習

來源:互聯網
上載者:User

標籤:ati   基礎   work   ica   public   動態代理   異常   color   turn   

什麼是AOP

 AOP 面向切面編程

採取橫向抽取機制,取代了傳統縱向繼承體系重複性代碼(效能監控、交易管理、安全檢查、緩衝)

 Spring AOP使用純Java實現,不需要專門的編譯過程和類載入器,在運行期通過代理方式向目標類織入增強代碼

 AspecJ是一個基於Java語言的AOP架構,Spring2.0開始,Spring AOP引入對Aspect的支援,AspectJ擴充了Java語言,提供了一個專門的編譯器,在編譯時間提供橫向代碼的織入

AOP底層原理

就是代理機制:

* 動態代理:(JDK中使用)

* JDK的動態代理,對實現了介面的類組建代理程式.

Spring的AOP代理

JDK動態代理:對實現了介面的類組建代理程式。沒有實現介面的類,就無法組建代理程式對象了。

CGLib代理機制:對類組建代理程式

結論:Spring架構,如果類實現了介面,就使用JDK的動態代理組建代理程式對象,如果這個類沒有實現任何介面,使用CGLIB組建代理程式對象.

AOP的術語

Joinpoint(連接點):所謂連接點是指那些被攔截到的點。在spring中,這些點指的是方法,因為spring只支援方法類型的連接點.

Pointcut(切入點):所謂切入點是指我們要對哪些Joinpoint進行攔截的定義.

Advice(通知/增強):所謂通知是指攔截到Joinpoint之後所要做的事情就是通知.通知分為前置通知,後置通知,異常通知,最終通知,環繞通知(切面要完成的功能)

Introduction(引介):引介是一種特殊的通知在不修改類代碼的前提下, Introduction可以在運行期為類動態地添加一些屬性方法.

Target(目標對象):代理的目標對象

Weaving(織入):是指把增強應用到目標對象來建立新的代理對象的過程.

spring採用動態代理織入,而AspectJ採用編譯期織入和類裝在期織入

Proxy(代理):一個類被AOP織入增強後,就產生一個結果代理類

Aspect(切面):是切入點和通知(引介)的結合

 

不帶有切點的切面

Spring按照通知Advice在目標方法的連接點位置,通知Advice可分為五類

前置通知:org.springframework.aop.MethodBeforeAdvice,在目標方法執行之前實施增強

後置通知:org.springframework.aop.AfterReturningAdvice,在目標方法執行之後實施增強

環繞通知:org.aopalliance.intercept.MethodInterceptor,在目標方法執行前後實施增強

異常拋出通知:org.springframework.aop.ThrowsAdvice,在方法拋出異常之後實施增強

引介通知:org.springframework.aop.IntroductionInterceptor,在目標類中添加一些新的方法和屬性

Spring中切面的類型:

Advisor:Spring中的傳統切面。

Aspect:都是有一個切點和一個通知的組合

Advisor:多個切點和多個通知的組合

 

Advisor : 代表一般切面,Advice本身就是一個切面,對目標類所有方法進行攔截(*不帶有切點的切面)

PointcutAdvisor : 代表具有切點的切面,可以指定攔截目標類哪些方法帶有切點的切面,針對某個方法進行攔截

 IntroductionAdvisor : 代表引介切面,針對引介通知而使用切面(不要求掌握)

不帶切點的切面執行個體

匯入相應的jar包:Spring開發基礎包、spring-aop-4.3.7.RELEASE.jar、aopalliance-1.0.jar(AOP聯盟包)

編寫一個介面Customer:

package com.js.aopStu; public interface CustomerDao {    public void add();    public void delete();    public void update();    public void find();}

編寫實作類別CustomerImpl:

package com.js.aopStu; public class CustomerImpl implements CustomerDao {     @Override    public void add() {            System.out.println("添加客戶...");    }     @Override    public void delete() {            System.out.println("刪除客戶...");    }     @Override    public void update() {            System.out.println("修改客戶...");    }     @Override    public void find() {        System.out.println("查詢客戶...");    } }

編寫增強代碼。建立一個類MyBeforeAdvice,以前置增強為例

package com.js.aopStu; import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; /** * 前置增強 * 實現指定介面 * @author hdb * */public class MyBeforeAdvice implements MethodBeforeAdvice{    /**     * method:執行的方法     * args:參數     * target:目標對象     */    @Override    public void before(Method method, Object[] args, Object target) throws Throwable {        System.out.println("前置增強...");    }    }

配置代理組建代理程式類,基於ProxyFactoryBean類,底層自動選擇使用JDK的動態代理還是CGLIB的代理。

配置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:util="http://www.springframework.org/schema/util"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"><!-- 定義目標對象 --><bean id="customerDao" class="com.js.aopStu.CustomerImpl"></bean><!-- 定義增強 --><bean id="beforeAdice" class="com.js.aopStu.MyBeforeAdvice"></bean> <!-- Spring支援配置來組建代理程式,基於ProxyFactoryBean類,底層自動選擇使用JDK的動態代理還是CGLIB的代理 --> <bean id="customerDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 設定目標對象 -->     <property name="target" ref="customerDao"></property>     <!-- 設定實現的介面,value中寫介面的全路徑 -->     <property name="proxyInterfaces" value="com.js.aopStu.CustomerDao"></property>     <!-- 配置需要攔截的,一定是value,此處對customerDao中的所有方法攔截 -->     <property name="interceptorNames" value="beforeAdice"></property> </bean></beans>

 

我們需要配置一些屬性,不需要都設定。

lProxyFactoryBean常用可配置屬性•target : 代理的目標對象•proxyInterfaces : 代理要實現的介面•如果多個介面可以使用以下格式賦值

<list>

    <value></value>

    ....

</list>

•proxyTargetClass : 是否對類代理而不是介面,設定為true時,使用CGLib代理•interceptorNames : 需要織入目標的Advice•singleton : 返回代理是否為單一實例,預設為單例•optimize : 當設定為true時,強制使用CGLib(proxyInterfaces、proxyTargetClass二者互斥,不能同時存在)

編寫測試類別:

package com.js.aopStu;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:applicationContext.xml")public class TestAOPDemo1 {        @Autowired    @Qualifier("customerDaoProxy")    private CustomerDao customerDao;        //不使用增強情況下    @Test    public void Demo1(){        customerDao.add();        customerDao.delete();        customerDao.find();        customerDao.update();    }}
帶有切點的切面(常用)用PointcutAdvisor實作類別,它有兩個介面:1、DefaultPointcutAdvisor:最常用的切面類型,它可以通過任意Pointcut和Advice 組合定義切面2、RegexpMethodPointcutAdvisor:構造 Regex切點切面一般使用這種。帶有切點的切面執行個體

建立一個DAO,建立被代理對象:

package com.js.demo3;/** * 目標對象 * @author  hdb * */public class OrderDao {    public void add() {            System.out.println("添加訂單...");    }    public void delete() {            System.out.println("刪除訂單...");    }    public void update() {            System.out.println("修改訂單...");    }    public void find() {        System.out.println("查詢訂單...");    }}

編寫增強類,這次使用環繞增強:

package com.js.demo3; import org.aopalliance.intercept.MethodInterceptor;import org.aopalliance.intercept.MethodInvocation; /** * 增強類 * 使用的是環繞增強 * @author hbd * */public class MyAroundAdvice implements MethodInterceptor{     @Override    public Object invoke(MethodInvocation methodInvocation) throws Throwable {        System.out.println("環繞前增強===");        Object object=methodInvocation.proceed();//執行目標對象的方法        System.out.println("環繞後增強===");        return object;    }    }

組建代理程式:通過配置的方式:

<?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:util="http://www.springframework.org/schema/util"       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"><!-- 帶有切點的切面 --><!-- 定義目標對象 --><bean id="orderDao1" class="com.js.demo3.OrderDao"></bean><!-- 定義增強 --><bean id="aroundAdvice" class="com.js.demo3.MyAroundAdvice"></bean><!-- 定義切點切面: --><bean id="myPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">    <!-- 定義運算式,規定哪些方法執行攔截 -->    <!-- . 任一字元  * 任意個 -->    <!-- <property name="pattern" value=".*"/> -->    <!-- <property name="pattern" value="cn\.itcast\.spring3\.demo4\.OrderDao\.add.*"/> -->    <!-- <property name="pattern" value=".*add.*"></property> -->    <property name="patterns" value=".*add.*,.*find.*"></property>    <!-- 應用增強 -->    <property name="advice" ref="aroundAdvice"/></bean><!-- 定義組建代理程式對象 --><bean id="orderDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">    <!-- 配置目標 -->    <property name="target" ref="orderDao1"></property>    <!-- 針對類的代理 -->    <property name="proxyTargetClass" value="true"></property>    <!-- 在目標上應用增強 -->    <property name="interceptorNames" value="myPointcutAdvisor"></property></bean></beans>

編寫測試類別:

package com.js.demo3;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:applicationContext.xml")public class TestAOPDemo1 {
@Autowired @Qualifier("orderDaoProxy") private OrderDao orderDao;
@Test public void demo1(){ orderDao.add(); orderDao.delete(); orderDao.find(); orderDao.update(); }}

 

Spring AOP學習

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.