第六節(jié) Hasor Aop

2018-09-28 19:32 更新

“面向切面編程”也被稱為“Aop”,是目前非常活躍的一個(gè)開(kāi)發(fā)思想。利用 AOP 可以對(duì)業(yè)務(wù)邏輯的各個(gè)部分進(jìn)行隔離,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的 可重用性,同時(shí)提高了開(kāi)發(fā)的效率。


Aop 編程的目的是將例如日志記錄、性能統(tǒng)計(jì)、安全控制、事務(wù)、異常處理等代碼從業(yè) 務(wù)邏輯代碼中劃分出來(lái)。


比方說(shuō)我有一個(gè)查詢用戶信息的接口,現(xiàn)在要為這個(gè)接口添加記錄的功能。每當(dāng)執(zhí)行一 次查詢都記錄下查詢消耗時(shí)間。如果我要實(shí)現(xiàn)這個(gè)功能,一般情況下需要在接口實(shí)現(xiàn)類的每 一個(gè)方法前后都要安插代碼來(lái)收集數(shù)據(jù)。如果這樣做的話會(huì)比較繁瑣,但是通過(guò) Aop 的方式 就顯得非常優(yōu)雅。


實(shí)現(xiàn) Aop 編程模型分為(靜態(tài)代理、動(dòng)態(tài)代理)兩種方式,其中靜態(tài)代理多以代理模式 (Proxy Pattern)的形式出現(xiàn)。而動(dòng)態(tài)代理則花樣繁多,常見(jiàn)的有:Java 原生的 Propxy、 CGLib、JBossAOP、等。


A.靜態(tài)代理


假設(shè)有一個(gè)工廠,工廠里的工人上下班每次都需要打卡。那么這個(gè)工廠的工人可以抽象為 Worker 接口、工作可以被抽象成為 doWork 方法。一個(gè)對(duì)象化的工人就構(gòu)建出來(lái)了如下:

public interface Worker {
    public void doWork();
}


打卡分為上班打卡和下班打卡,為此抽象一個(gè)打卡機(jī),并將上下班打卡使用 beforeWork 和 afterWork 方法表示。如下:

public class Machine {
    public void beforeWork() {
        ...
    }
    public void afterWork() {
        ...
    }
}


工廠規(guī)定每個(gè)員工只要來(lái)到工廠就視為上班打卡、當(dāng)離開(kāi)工廠就被認(rèn)為下班打卡。為了 人性化考勤,公司使用了一種現(xiàn)代化的技術(shù)可以讓員工不必自己動(dòng)手去打卡,猶如配備了一 名貼身小秘書(shū)。


其實(shí)不難看出這項(xiàng)新技術(shù)僅僅是圍繞著工人(Worker)在工作(doWork)前后實(shí)現(xiàn)了自動(dòng)打卡。下面是這個(gè)技術(shù)的抽象:

public class WorkerProxy implements Worker {
    private Machine machine;
    private Worker targetWorker;
    public void doWork() {
        this.machine.beforeWork();
        this.targetWorker.doWork();
        this.machine.afterWork();
    }
}


B.動(dòng)態(tài)代理


在靜態(tài)代理中所有類型都是衡定的。在程序執(zhí)行時(shí),代理類(WorkerProxy)的 class文件已經(jīng)預(yù)先存在。在動(dòng)態(tài)代理中這卻恰恰相反的,代理類不會(huì)預(yù)先存在,當(dāng)需要它的時(shí)候通過(guò)一些專門(mén)的類庫(kù)創(chuàng)建這個(gè)代理程序。


比方說(shuō)一個(gè)程序中有多種不同的 Servies 類。我們要打印出調(diào)用每個(gè)業(yè)務(wù)方法所占用的 時(shí)間。如果使用靜態(tài)代理方式會(huì)發(fā)現(xiàn),程序中根本不存在衡定的“doWorker”方法。


雖然不存在衡定的“doWorker”方法,但是調(diào)用行為是存在的。而且可以將其行為抽象 出來(lái)這就是 Aop 中的“切面”,負(fù)責(zé)執(zhí)行這個(gè)切面的類就叫“攔截器”。下面這個(gè)代碼展示 了如何用 Java 的原生支持實(shí)現(xiàn)動(dòng)態(tài)代理。

ClassLoader lod = Thread.currentThread().getContextClassLoader();
Class<?>[] faceSet = new Class[] { TestBean2_Face.class };
Object proxy = Proxy.newProxyInstance(
        lod, faceSet, new JavaInvocationHandler()
);
TestBean2_Face face = (TestBean2_Face) proxy;
System.out.println(face.toString());


下面的攔截器就是上面例子中用到的:“JavaInvocationHandler”類。

class JavaInvocationHandler implements InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args) {
        return null; // TODO Auto-generated method stub
     }
 }


由此可見(jiàn)在 Java 中實(shí)現(xiàn)一個(gè)動(dòng)態(tài)代理還算很簡(jiǎn)單的,但是有的時(shí)候我們想把所有 Bean 都管理起來(lái)。并且按照自己的意愿來(lái)對(duì)其進(jìn)行動(dòng)態(tài)代理,在這種要求下我們不得不自己去開(kāi)發(fā)一套 Bean 管理程序,或者使用更為成熟的框架例如:Spring、Guice、或者您也可以使用 Hasor 進(jìn)行 Bean 的管理。


Hasor 的方式


Hasor 的 Aop 聲明使用方式和 JDK 自帶的很相似,但是由于 Hasor 具有 Bean 管理的功能,因此 Hasor 很容易在一批 Bean 上使用動(dòng)態(tài)代理功能。這將會(huì)大大減少重復(fù)代碼的開(kāi)發(fā),而且 Hasor 還可以通過(guò)匹配器讓您自己框選符合條件的 Bean,不同于 Spring 的是 Hasor 提供的 Api 更加注重編程性而非配置聲明。


public class SimpleInterceptor implements MethodInterceptor {
    public Object invoke(MethodInvocation invocation) throws Throwable {
        try {
            System.out.println("before...");
            Object returnData = invocation.proceed();
            System.out.println("after...");
            return returnData;
        } catch (Exception e) {
            throw e;
        }
    }
}


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)