1. 程式人生 > >Spring系列之六:AOP的代理詳解

Spring系列之六:AOP的代理詳解

Aop是面向切片的程式設計,首先先用圖解釋AOP的程式設計

這是沒有用aop的情況,程式碼中存在大量的重複的程式碼:


使用aop就是採用一個切片,對封裝好的程式進行切開,減少重複的程式碼,對重複的程式碼進行復用:


那麼如何實現這種aop的切片程式設計了?就是使用動態代理的方式,為方法增加方法,現在就講一講代理的原理:

代理就相當於處於一箇中間層,當一個物件不能呼叫另一個物件的方法時候,可以通過代理進行呼叫。

首先是靜態代理:

        靜態代理相當於首先定義了一個介面,介面中有個方法,出於不同的需要,我們有很多子類實現了這個介面並重寫了這個介面中的方法(被代理類)。靜態代理處於中間層不斷呼叫代理類。

下面給出實現代理的原始碼:

1.介面的實現

/**
 * Subject介面的實現
 */
public interface Subject {
    void visit();
}

2.產生被代理類

/**
 * Subject介面的實現
 */
public class SubjectImpl implements Subject {
    public void visit() {
        System.out.println("SubjectImpl!");
}
}

3.中間層代理類

public class ProxySubject implements Subject {
    private 
Subject subject; public ProxySubject(Subject subject) { this.subject = subject; } public void visit() { subject.visit(); } }

4.使用代理類

public class Client {
    public static void main(String[] args) {
        ProxySubject subject=new ProxySubject(new SubjectImpl());
subject.visit();
} }

由此可以看到,我們對介面中的方法進行了擴充。aop中使用代理就是對方法進行擴充

現在講一講動態代理:

    由上面的例子可以看出,你對介面中的方法進行擴充的時候,你每次都要進行新建一個類,給代理類進行呼叫,以後程式越寫越多就會十分麻煩,那這個時候就要用到動態代理,就在產生的被代理類上進行擴充,而不需要頻繁的進行建類

下面給出動態代理的實現原始碼:

1.介面類

/**
 * Subject介面的實現
 */
public interface Subject {
    void visit();
}

2.被代理類

/**
 * Subject介面的實現
 */
public class SubjectImpl implements Subject {
    public void visit() {
        System.out.println("SubjectImpl!");
}
}
3.使用handler對被代理類進行擴充
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class Handler implements InvocationHandler {
    private Object target;
    public Handler(Object target) {
        this.target = target;
}

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("開始事務!");
method.invoke(target,args);
System.out.println("事務結束!");
        return null;
}
}

4.呼叫代理類

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Client {
    public static void main(String[] args)  {
        SubjectImpl subjectImpl=new SubjectImpl();
InvocationHandler handler=new Handler(subjectImpl);
Subject subject = (Subject) Proxy.newProxyInstance(subjectImpl.getClass().getClassLoader(),
subjectImpl.getClass().getInterfaces(),
handler);
subject.visit();
}
}

Proxy.newProxyInstance用於產生引數

第一個引數:ClassLoader loader:它是類載入器型別

第二個引數:Class[] interfaces:指定newProxyInstance()方法返回的物件要實現哪些介面,沒錯,可以指定多個介面

第三個引數:handler主要就是對方法增加內容

aop面向切片程式設計就是這樣為方法增加內容,aop主要使用Cglin代理和動態代理,動態代理傳入的是個介面,而cglib闖入是物件,Spirng自行選擇該使用何種方法。總之是為了在原基礎上增加內容。