動態代理模擬簡單的AOP

參照MOOC<java核心技術高階>,使用java動態代理來實現一個簡單的AOP

AOP vs. OOP

OOP

面向對象編程,將功能需求劃分爲獨立的、不同的、功能完善的類,通過繼承、多態等方式實現相同或者不同的行爲

AOP

面向切面編程,將通用的需求功能從衆多類中提取出來,使得衆多類共享一個行爲。

關係

AOP是OOP的補充
OOP的不足之一關鍵業務和非關鍵業務的耦合。
如僱員類Employee,核心業務是work,非核心的業務(高可變性)是記錄(record) work前
後的狀態信息,比如開始時間、使用的工具等,隨着需求可能不斷變化。
如果只使用OOP,那麼要把非關鍵業務代碼record寫入類中,一方面是耦合性高,另一方面是這種
高可變性的業務可能造成修改頻繁,難以維護。
如何將非關鍵業務從耦合中分離出來,統一管理,便於修改? --AOP

怎麼實現AOP?
java動態代理的特性很適合AOP。
動態代理會攔截特定的方法調用,進行加工(添加非關鍵的業務),在調用真正的業務方法。

利用動態代理實現一個SimpleAOP

場景描述:

有Person類,關鍵業務是eat,非關鍵業務是在eat之前洗手(wash hands),
eat之後擦嘴(wipe mouth)

具體步驟:
1- 創建Person接口

public interface Person {
    void eat();
    String getName();
}

2- 實現Person

public class PersonImpl implements Person {
    private String name;
    public PersonImpl(String name){
        this.name =name;
    }
    @Override
    public void eat(){
        System.out.println(name+" is eating!");
    }

    @Override
    public String getName() {
        return name;
    }

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

3- 創建調用處理器(實現InvocationHandler)

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class PersonProxyHandler implements InvocationHandler {
    private Person person;//持有真正被調用的對象
    public PersonProxyHandler(Person p){
        this.person=p;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
        //before eat
        System.out.println(person.getName()+" is washing hands!");
        //eat
        Object res = method.invoke(person,args);
        //after eat
        System.out.println(person.getName()+" is wiping mouth!");
        return res;
    }
}

4- 生成動態代理並調用方法

import java.lang.reflect.Proxy;
public class Main {
    public static void main(String[] args) {
        //創建目標對象
        PersonImpl edwinxu = new PersonImpl("Edwin0");
        //創建調用處理器對象
        PersonProxyHandler pph = new PersonProxyHandler(edwinxu);
        //動態生成代理對象
        Person personProxy = (Person) Proxy.newProxyInstance(
                PersonImpl.class.getClassLoader(),PersonImpl.class.getInterfaces(),pph
        );
        while (true){
            try {
                personProxy.eat();//執行關鍵業務代碼
                edwinxu.setName("Edwin"+(int)(Math.random()*10));
                Thread.sleep(3000);
                System.out.println();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}

特殊說明:

要模仿AOP,按道理理應使用配置文件形式,但是這裏簡化了。

輸出:

Edwin0 is washing hands!
Edwin0 is eating!
Edwin0 is wiping mouth!

Edwin5 is washing hands!
Edwin5 is eating!
Edwin5 is wiping mouth!

可見通過動態代理,在關鍵業務(eat)上添加了一些其他的高可變的非關鍵業務。

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