在傳統的面向對象思想中,若是想要實現功能複用,要麼繼承,要麼引用,不管哪一種方式,對代碼都有必定的侵入性,耦合無可避免java
若是你想用它加強你程序的功能,你必須改動你的程序代碼,那它就具備侵入性! 若是隻有一兩點須要加強還好說,但若是大量功能點須要被加強,那麼工做量就會很大,代碼也不優雅! 想象一下,若是你對外公開了一系列接口,忽然領導說了,接口要加權限控制。在哪加? 最笨的固然是寫個程序驗證邏輯,而後每一個接口都拿來調用一遍。 這也是面向對象的思想短板,在要爲程序新增一些通用功能時,只能經過耦合的方式才能進行。 而代理(動態代理)就能很好的解決該問題!git
public interface Subject {
void sayGoodBye();
void sayHello(String str);
boolean isProxy();
}
複製代碼
public class RealSubject implements Subject {
@Override
public void sayGoodBye() {
System.out.println("RealSubject 我是原封不動的代碼 sayGoodBye ");
}
@Override
public void sayHello(String str) {
System.out.println("RealSubject 我是原封不動的代碼 sayHello " + str);
}
@Override
public boolean isProxy() {
System.out.println("RealSubject 我是原封不動的代碼 isProxy ");
return false;
}
}
複製代碼
public class ProxySubject implements Subject {
private Subject subject;
public ProxySubject(Subject subject) {
this.subject = subject;
}
@Override
public void sayGoodBye() {
//代理類,功能的加強 調用前 sayGoodBye 可作操做(好比是否能調用的權限認證)
System.out.println("ProxySubject sayGoodBye begin " +
"代理類,功能的加強 調用前 sayGoodBye 可作操做(好比是否能調用的權限認證)");
//在代理類的方法中 間接訪問被代理對象的方法
subject.sayGoodBye();
System.out.println("ProxySubject sayGoodBye end " +
"這裏可處理原方法調用後的邏輯處理");
}
@Override
public void sayHello(String str) {
//代理類,功能的加強 調用前 sayHello 可作操做(好比是否能調用的權限認證) 並測試帶參數的方法
System.out.println("ProxySubject sayHello begin " +
"代理類,功能的加強 調用前 sayHello 可作操做(好比是否能調用的權限認證)");
//在代理類的方法中 間接訪問被代理對象的方法
subject.sayHello(str);
System.out.println("ProxySubject sayHello end " +
"這裏可處理原方法調用後的邏輯處理");
}
@Override
public boolean isProxy() {
//代理類,功能的加強 調用前 isProxy 可作操做(好比是否能調用的權限認證) 並測試帶返回的方法
System.out.println("ProxySubject isProxy begin " +
"代理類,功能的加強 調用前 isProxy 可作操做(好比是否能調用的權限認證)");
boolean boolReturn = subject.isProxy();
System.out.println("ProxySubject isProxy end " +
"這裏可處理原方法調用後的邏輯處理");
return boolReturn;
}
}
複製代碼
public class ProxyMain {
public static void main(String[] args) {
//被代理的對象,某些狀況下 咱們不但願修改已有的代碼,咱們採用代理來間接訪問
RealSubject realSubject = new RealSubject();
//代理類對象,將原有代碼不想修改的對象傳入代理類對象
ProxySubject proxySubject = new ProxySubject(realSubject);
//調用代理類對象的方法
proxySubject.sayGoodBye();
System.out.println("******");
proxySubject.sayHello("Test");
System.out.println("******");
proxySubject.isProxy();
}
}
複製代碼
ProxySubject sayGoodBye begin 代理類,功能的加強 調用前 sayGoodBye 可作操做(好比是否能調用的權限認證)
RealSubject 我是原封不動的代碼 sayGoodBye
ProxySubject sayGoodBye end 這裏可處理原方法調用後的邏輯處理
******
ProxySubject sayHello begin 代理類,功能的加強 調用前 sayHello 可作操做(好比是否能調用的權限認證)
RealSubject 我是原封不動的代碼 sayHello Test
ProxySubject sayHello end 這裏可處理原方法調用後的邏輯處理
******
ProxySubject isProxy begin 代理類,功能的加強 調用前 isProxy 可作操做(好比是否能調用的權限認證)
RealSubject 我是原封不動的代碼 isProxy
ProxySubject isProxy end 這裏可處理原方法調用後的邏輯處理
複製代碼
靜態代理(傳統代理模)的實現方式比較暴力直接,須要將全部被代理類的全部方法都寫一遍,而且一個個的手動轉發過去,麻煩並繁瑣。因此咱們要學習並使用動態代理。github
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
複製代碼
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {....}
複製代碼
public interface Subject {
void sayGoodBye();
void sayHello(String str);
boolean isProxy();
}
複製代碼
public class RealSubject implements Subject {
@Override
public void sayGoodBye() {
System.out.println("RealSubject 我是原封不動的代碼 sayGoodBye ");
}
@Override
public void sayHello(String str) {
System.out.println("RealSubject 我是原封不動的代碼 sayHello " + str);
}
@Override
public boolean isProxy() {
System.out.println("RealSubject 我是原封不動的代碼 isProxy ");
return false;
}
}
複製代碼
public class SubjectInvocationHandler implements InvocationHandler {
//這個就是咱們要代理的真實對象
private Object subject;
//構造方法,給咱們要代理的真實對象賦初值
public SubjectInvocationHandler(Object subject) {
this.subject = subject;
}
@Override
public Object invoke(Object object, Method method, Object[] args) throws Throwable {
//在代理真實對象前咱們能夠添加一些本身的操做
System.out.println("before Method invoke 代理類,功能的加強 調用前 "+method+" 可作操做(好比是否能調用的權限認證)");
System.out.println("Method:" + method);
//當代理對象調用真實對象的方法時,其會自動的跳轉到代理對象關聯的handler對象的invoke方法來進行調用,獲得對應的返回值,最後將對應返回值返回
Object obj = method.invoke(subject, args);
//在代理真實對象後咱們也能夠添加一些本身的操做
System.out.println("after Method invoke 這裏可處理原方法調用後的邏輯處理 ");
return obj;
}
}
複製代碼
public class ProxyMain {
public static void main(String[] args) {
//被代理類
Subject realSubject = new RealSubject();
//咱們要代理哪一個類,就將該對象傳進去,最後是經過該被代理對象來調用其方法的
SubjectInvocationHandler handler = new SubjectInvocationHandler(realSubject);
//生成代理類
Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(), handler);
//輸出代理類對象
System.out.println("Proxy : " + subject.getClass().getName());
System.out.println("Proxy super : " + subject.getClass().getSuperclass().getName());
System.out.println("Proxy interfaces : " + subject.getClass().getInterfaces()[0].getName());
//調用代理類sayGoodBye方法
subject.sayGoodBye();
System.out.println("--------");
//調用代理類sayHello方法
subject.sayHello("Test");
System.out.println("--------");
System.out.println("---subject.isProxy()-----" + subject.isProxy());
}
}
複製代碼
Proxy : com.sun.proxy.$Proxy0
Proxy super : java.lang.reflect.Proxy
Proxy interfaces : staticproxy.Subject
before Method invoke 代理類,功能的加強 調用前 public abstract void staticproxy.Subject.sayGoodBye() 可作操做(好比是否能調用的權限認證)
Method:public abstract void staticproxy.Subject.sayGoodBye()
RealSubject 我是原封不動的代碼 sayGoodBye
after Method invoke 這裏可處理原方法調用後的邏輯處理
--------
before Method invoke 代理類,功能的加強 調用前 public abstract void staticproxy.Subject.sayHello(java.lang.String) 可作操做(好比是否能調用的權限認證)
Method:public abstract void staticproxy.Subject.sayHello(java.lang.String)
RealSubject 我是原封不動的代碼 sayHello Test
after Method invoke 這裏可處理原方法調用後的邏輯處理
--------
before Method invoke 代理類,功能的加強 調用前 public abstract boolean staticproxy.Subject.isProxy() 可作操做(好比是否能調用的權限認證)
Method:public abstract boolean staticproxy.Subject.isProxy()
RealSubject 我是原封不動的代碼 isProxy
after Method invoke 這裏可處理原方法調用後的邏輯處理
---subject.isProxy()-----false
---subject.isProxy()-----false
複製代碼