1. 程式人生 > >JDK動態代理[1]---靜態代理和動態代理

JDK動態代理[1]---靜態代理和動態代理

靜態代理

  • 定義介面

public interface Subject {
    void visit();
}
  • 建立真正實現的類

public class RealSubject implements Subject {
    private String name = "proxy.state";

    @Override
    public void visit() {
        System.out.println(name);
    }
}
  • 建立靜態代理類
public class ProxySubject implements Subject {

    private Subject subject;

    public ProxySubject(Subject subject) {
        this.subject = subject;
    }

    @Override
    public void visit() {
        subject.visit();
    }
}
  • 使用例子
public class Client {

    public static void main(String[] args) {
        ProxySubject subject = new ProxySubject(new RealSubject());
        subject.visit();
        RealSubject realSubject = new RealSubject();
        realSubject.visit();
    }
}

靜態代理類優缺點

代理類接受一個Subject介面的物件,任何實現該介面的物件,都可以通過代理類進行代理,增加了通用性。
但是也有缺點,每一個代理類都必須實現一遍委託類(也就是realsubject)的介面,
如果介面增加方法,則代理類也必須跟著修改。
其次,代理類每一個介面物件對應一個委託物件,
如果委託物件非常多,則靜態代理類就非常臃腫,難以勝任。

動態代理類

  • 定義介面

public interface Subject {
    void visit();
}
  • 建立真正實現的類

public class RealSubject implements Subject {
    private String name = "proxy.dynamic";

    @Override
    public void visit() {
        System.out.println(name);
    }
}
  • 建立動態代理類
public class DynamicProxy implements InvocationHandler {
    private Object object;

    public DynamicProxy(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        before(methodName);
        Object result = method.invoke(object, args);
        after(methodName);
        return result;
    }

    /**
     * 前置通知
     * @param method
     */
    public void before(String method){
        System.out.println("before the method of "+method);

    }

    /**
     * 後置通知
     * @param method
     */
    public void after(String method){
        System.out.println("after the method of "+method);
    }
}
  • 使用例子
public class Client {

    public static void main(String[] args) {
        Subject realSubject = new RealSubject();
        DynamicProxy proxy = new DynamicProxy(realSubject);
        ClassLoader classLoader = realSubject.getClass().getClassLoader();
        Subject subject = (Subject) Proxy.newProxyInstance(classLoader, new Class[]{Subject.class}, proxy);
        subject.visit();
    }

}

動態代理總結

之前我們發現了靜態代理會產生許多重複程式碼,不能很好的進行程式碼複用,而動態代理能夠很好的解決這個問題,代理類TransactionHandler實現了InvocationHandler介面,並且它持有的目標物件型別是Object,因此事務控制代理類TransactionHandler能夠代理任意的物件,為任意的物件新增事務控制的邏輯。因此動態代理才真正的將程式碼中橫向切面的邏輯剝離了出來,起到程式碼複用的目的。但是動態代理也有缺點,一是它的實現比靜態代理更加複雜也不好理解;二是它存在一定的限制,例如它要求需要代理的物件必須實現了某個介面;三是它不夠靈活,動態代理會為介面中的宣告的所有方法新增上相同的代理邏輯。當然,這只是JDK動態代理所存在的一些缺陷,動態代理還有另外的實現如使用CGLIB庫