AOP編程簡介及其在Spring框架中的使用

AOP編程簡介及其在Spring框架中的使用


額,最近一直沒來逛自己的博客發現遊客蠻多的:),從前段時間開始就一直在學ssh框架(已經搞定strut2和hibernate),javaweb的框架還是蠻多的吧,現在的ssm好像比較流行,不過既然手頭有本ssh的書再加上自己沒學過框架的知識,所以就先從ssh入手了。那這兩天呢學了aop面向切面編程,所以就沒忘來自己博客寫一篇。也算是鞏固一下自己知識。

aop編程:
AOP與OOP互爲補充,面向對象編程(OOP)將程序分解成各個層次的對象;面向切面編程(AOP)則是將程序運行過程中分解成各個切面。可以說OOP是從靜態角度考慮程序結構而AOP是從動態角度考慮的。

AOP並不與某個具體類耦合。具有兩個特性:1.各步驟之間具有良好的隔離性2.源代碼無關性。
AOP的一些術語:
1.切面(aspect):切面用於組織多個advice,advice在切面中定義。
2.連接點(joinpoint):程序執行過程中明確的點,在spring中,連接點總是方法的調用。
3.增強處理(advice):AOP框架在特定切入點執行增強處理。
4.切入點(pointcut):可以插入增強處理的連接點。


OK!接下來代碼演示吧,實例永遠比空洞的知識強。

本實例是使用基於註解的方式,另外還有基於xml的。
先把實例必須的兩個javabean貼出

package Before;
//定義一個hello接口
public interface Hello {
//hello的兩個方法
    public void foo();
    public int addUser(String name ,String pass);
}
package Before;

import org.springframework.stereotype.Component;
//註解component指定此爲id爲hello的bean
//實現接口並實現方法
@Component("hello")
public class HelloImpl implements Hello {

    @Override
    public void foo() {
        System.out.println("執行hello主鍵的foo方法");
    }

    @Override
    public int addUser(String name,String pass) {
        System.out.println("執行hello組鍵的adduser組鍵"+name);
        return 20;
    }

}

一.定義before增強處理
定義一個切面,定義一個before增強處理:

package Before;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

//定義一個切面
@Aspect
public class AuthAspect {

    //所有方法的執行作爲切入點
    //括號中的是切入點表達式,文章最後進行介紹
    @Before("execution(* Before.*.*(..))")
    public void authority(){
        System.out.println("模擬進行權限檢查");
    }
}

以下是spring配置文件:

<!--beans.xml spring的配置文件 -->
<?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:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-4.0.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
    <!-- 自動搜索Bean組件 自動搜索切面類 -->
    <context:component-scan base-package="Before">
        <context:include-filter type="annotation"
            expression="org.aspectj.lang.annotation.Aspect"/>
    </context:component-scan>
    <!-- 啓動@AspectJ支持 -->
    <aop:aspectj-autoproxy/>
</beans>

ok,接下來我們來寫一個測試類

package Before;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AspectTest {
    public static void main(String[] args) {
                // 創建Spring容器
                ApplicationContext ctx = new
                    ClassPathXmlApplicationContext("beans.xml");
                Hello hello = ctx.getBean("hello" , Hello.class);
                hello.foo();
                hello.addUser("孫悟空" , "7788");
    }
}

上面的所有步驟全部搞定,運行,結果如下
這裏寫圖片描述
對比我們不進行AOP處理的結果:
這裏寫圖片描述
結果很明顯,這就是aop的作用,在不改動源代碼的基礎上,對源代碼進行增強處理。


2.AfterReturning增強處理
AfterReturning有的屬性值指定形參名,回限制目標方法必須有符合這兩個形參。
不多說,貼代碼

package AfterReturning;

import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class LogAspect {
    @AfterReturning(returning="rvt", pointcut="execution(* Before.*.*(..)) && args(pass,name)")
    //聲明rvt時指定的類型會限制目標方法必須有返回值或者沒有返回值
    public void log(Object rvt,String pass,String name){
        System.out.println("第一個參數"+pass);
        System.out.println("第二個參數"+name);
        System.out.println("獲取目標方法的返回值"+rvt);
        System.out.println("模擬記錄日誌功能。。。");
    }
}

結果(此結果加上before處理後的結果):
這裏寫圖片描述
看出差別了吧。


Afterthrowing增強處理

package AfterThrowing;

import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class RepairAspect {

    @AfterThrowing(throwing="ex",pointcut="execution(* Before.*.*(..))")
    public void doRecoveryActions11(Throwable ex){
        System.out.println("目標方法拋出的異常"+ex);
        System.out.println("模擬advice對異常的修復....");
    }
}

該寫一下前面的helloimpl類

package Before;

import org.springframework.stereotype.Component;

@Component("hello")
public class HelloImpl implements Hello {

    @Override
    public void foo() {
        System.out.println("執行hello主鍵的foo方法");
    }

    @Override
    public int addUser(String name,String pass) {
        System.out.println("執行hello組鍵的adduser組鍵"+name);
        if(name.length()<=3||name.length()>=10){
            throw new IllegalArgumentException("name的參數必須大於3小於10");
        }
        return 20;
    }

}

在xml文件中加入切面類所在的包,結果如下
這裏寫圖片描述
可以看出,增強處理起作用了。


時間問題,after增強處理就不講了,很簡單,跟before差不多,只不過一個在目標方法之前,一個在後。


Around增強處理

貼代碼,兩點多了,有點困了,

package Around;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class TxAspect{

    @Around("execution(* Before.*.*(..))")
    public Object processTx (ProceedingJoinPoint jp) throws Throwable{
        System.out.println("執行目標方法之前,模擬開始事務.....");
        //獲取目方法原始的調用參數
        Object [] args=jp.getArgs();
        if(args!=null&&args.length>1){
            //修改目標方法調用參數的第一個參數
            args[0] ="【增加的前綴】"+args[0];
        }
        //以改變後的參數去執行目標方法,並保存目標方法返回的執行值
        Object rvt=jp.proceed(args);
        System.out.println("模擬事務結束........");
        if(rvt!=null&&rvt instanceof Integer){
            rvt=(Integer)rvt*(Integer)rvt;
        }
        return rvt;
    }
}

額,這個相對有點複雜,該類的方法processTx有個參數,就是代表目標方法,執行第一個輸出之後,必須重新調用這個目標方法讓他執行完再執第二個輸出。

配置xml,後執行測試類
這裏寫圖片描述

看到結果。和程序中描述的一樣。


注: execution(* Before..(..)) && args(pass,name)
第一個*表示目標方法的返回值任意。
第二個 第三個表示 任意類的任意方法
&&後面的表示對連接點的參數類型進行限制,可以過濾目標方法。

ok ,這隻能說是AOP的皮毛,真正的AOP可以是一本書啊,這只是AOP框架在spring中的利用。減少不必要的編碼。寫的不具體,但至少能懂吧。具體還需要進一步學習。晚安,am2:18。

____jeker_chen

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