通過實例理解AOP

Aspect Oriented Programming  面向切面編程。解耦是程序員編碼開發過程中一直追求的。AOP也是爲了解耦所誕生。

具體思想是:定義一個切面,在切面的縱向定義處理方法,處理完成之後,回到橫向業務流。

AOP 在Spring框架中被作爲核心組成部分之一,的確Spring將AOP發揮到很強大的功能。最常見的就是事務控制。工作之餘,對於使用的工具,不免需要了解其所以然。學習了一下,寫了些程序幫助理解。

AOP 主要是利用代理模式的技術來實現的。


1、靜態代理:就是設計模式中的proxy模式

a、業務接口

複製代碼
/**
 * 抽象主題角色:聲明瞭真實主題和代理主題的共同接口。
 * 
 * @author yanbin
 * 
 */
public interface ITalk {

    public void talk(String msg);

}
複製代碼

b、業務實現

複製代碼
/**
 * 真實主題角色:定義真實的對象。
 * 
 * @author yanbin
 * 
 */
public class PeopleTalk implements ITalk {

    public String username;
    public String age;

    public PeopleTalk(String username, String age) {
        this.username = username;
        this.age = age;
    }

    public void talk(String msg) {
        System.out.println(msg + "!你好,我是" + username + ",我年齡是" + age);
    }

    public String getName() {
        return username;
    }

    public void setName(String name) {
        this.username = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

}
複製代碼

c、代理對象

複製代碼
/**
 * 代理主題角色:內部包含對真實主題的引用,並且提供和真實主題角色相同的接口。
 * 
 * @author yanbin
 * 
 */
public class TalkProxy implements ITalk {

    private ITalk talker;

    public TalkProxy(ITalk talker) {
        // super();
        this.talker = talker;
    }

    public void talk(String msg) {
        talker.talk(msg);
    }

    public void talk(String msg, String singname) {
        talker.talk(msg);
        sing(singname);
    }

    private void sing(String singname) {
        System.out.println("唱歌:" + singname);
    }

}
複製代碼

d、測試類

複製代碼
/**
 * 代理測試類,使用代理
 *
 * @author yanbin
 * 
 */
public class ProxyPattern {

    public static void main(String[] args) {
        // 不需要執行額外方法的。
        ITalk people = new PeopleTalk("AOP", "18");
        people.talk("No ProXY Test");
        System.out.println("-----------------------------");

        // 需要執行額外方法的(切面)
        TalkProxy talker = new TalkProxy(people);
        talker.talk("ProXY Test", "代理");
    }

}
複製代碼

從這段代碼可以看出來,代理模式其實就是AOP的雛形。 上端代碼中talk(String msg, String singname)是一個切面。在代理類中的sing(singname)方法是個後置處理方法。

這樣就實現了,其他的輔助方法和業務方法的解耦。業務不需要專門去調用,而是走到talk方法,順理成章的調用sing方法

再從這段代碼看:1、要實現代理方式,必須要定義接口。2、每個業務類,需要一個代理類。

2、動態代理:jdk1.5中提供,利用反射。實現InvocationHandler接口。

業務接口還是必須得,業務接口,業務類同上。

a、代理類:

複製代碼
/**
 * 動態代理類
 * 
 * @author yanbin
 * 
 */
public class DynamicProxy implements InvocationHandler {

    /** 需要代理的目標類 */
    private Object target;

    /**
     * 寫法固定,aop專用:綁定委託對象並返回一個代理類
     * 
     * @param delegate
     * @return
     */
    public Object bind(Object target) {
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    /**
     * @param Object
     *            target:指被代理的對象。
     * @param Method
     *            method:要調用的方法
     * @param Object
     *            [] args:方法調用時所需要的參數
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
        // 切面之前執行
        System.out.println("切面之前執行");
        // 執行業務
        result = method.invoke(target, args);
        // 切面之後執行
        System.out.println("切面之後執行");
        return result;
    }

}
複製代碼

b、測試類

複製代碼
/**
 * 測試類
 * 
 * @author yanbin
 * 
 */
public class Test {

    public static void main(String[] args) {
        // 綁定代理,這種方式會在所有的方法都加上切面方法
        ITalk iTalk = (ITalk) new DynamicProxy().bind(new PeopleTalk());
        iTalk.talk("業務說明");
    }
}
複製代碼

輸出結果會是:

切面之前執行
people talk業務說法
切面之後執行

說明只要在業務調用方法切面之前,是可以動態的加入需要處理的方法。

從代碼來看,如果再建立一個業務模塊,也只需要一個代理類。ITalk iTalk = (ITalk) new DynamicProxy().bind(new PeopleTalk());  將業務接口和業務類綁定到動態代理類。

但是這種方式:還是需要定義接口。

3、利用cglib

CGLIB是針對類來實現代理的,他的原理是對指定的目標類生成一個子類,並覆蓋其中方法實現增強。採用的是繼承的方式。不細說,看使用

a、業務類

複製代碼
/**
 * 業務類
 * 
 * @author yanbin
 * 
 */
public class PeopleTalk {

    public void talk(String msg) {
        System.out.println("people talk" + msg);
    }

}
複製代碼

b、cglib代理類

複製代碼
/**
 * 使用cglib動態代理
 * 
 * @author yanbin
 * 
 */
public class CglibProxy implements MethodInterceptor {

    private Object target;

    /**
     * 創建代理對象
     * 
     * @param target
     * @return
     */
    public Object getInstance(Object target) {
        this.target = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());
        // 回調方法
        enhancer.setCallback(this);
        // 創建代理對象
        return enhancer.create();
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object result = null;
        System.out.println("事物開始");
        result = methodProxy.invokeSuper(proxy, args);
        System.out.println("事物結束");
        return result;
    }

}
複製代碼

c.測試類

複製代碼
/**
 * 測試類
 * 
 * @author yanbin
 * 
 */
public class Test {

    public static void main(String[] args) {
        PeopleTalk peopleTalk = (PeopleTalk) new CglibProxy().getInstance(new PeopleTalk());
        peopleTalk.talk("業務方法");
        peopleTalk.spreak("業務方法");
    }

}
複製代碼

最後輸出結果:

事物開始
people talk業務方法
事物結束
事物開始
spreak chinese業務方法
事物結束

轉自:http://www.cnblogs.com/yanbincn/archive/2012/06/01/2530377.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章