代理模式&動態代理

動態代理的用途:java

動態代理的用途與裝飾模式很類似,就是爲了對某個對象進行加強。全部使用裝飾者模式的案例均可以使用動態代理來替換,動態代理能夠更好的解耦合ide

加強有3個手段
1. 繼承
 被加強對象不能變
 加強內容不能變
2. 裝飾者模式
 被加強對象可變
 但加強內容不能變
3. 動態代理
 被加強對象可變
 加強內容也可變
測試

如何實現動態代理?this

定義一個接口Interface, 被加強的對象的類都會實現這個接口spa

 public interface Interface {
 public void fun();
}

實現這個Interface接口:
而這個InterfaceImpl就是動態代理中被加強的內容
代理

 public class InterfaceImpl implements Interface {
 @Override
 public void fun() {
  System.out.println("目標方法調用");
 }
}

定義一個接口Advice, 加強內容的類都會實現這個接口
這個接口有兩個未實現的方法:
before()前置加強的方法
after()後置加強的方法
code

 public interface Advice {
 public void before();
 public void after();
}

而實現了Advice接口的對象就是動態代理中加強內容對象

JavaAPI:繼承

java.lang.reflect.Proxy接口

Object proxyObject = Proxy.newProxyInstance(ClassLoader classLoader, Class[] interfaces, InvocationHandler h);

返回一個指定接口的代理類實例,該接口能夠將方法調用指派到指定的調用處理程序

參數:
classLoader - 定義代理類的類加載器
interfaces - 代理類要實現的接口列表
h - 指派方法調用的調用處理程序
返回:
一個帶有代理類的指定調用處理程序的代理實例,它由指定的類加載器定義,並實現指定的接口


java.lang.reflect.InvocationHandler

public Object invoke(Object proxy, Method method, Object[] args);

這個invoke()方法在調用代理對象所實現接口中的方法時調用

* Object proxy:當前對象,即代理對象!在調用誰的方法!
* Method method:當前被調用的方法(目標方法)
* Object[] args:目標方法參數

調用proxy實例的方法時, 都會被InvocationHandler所捕獲, 所以只要實現InvocationHandler實現類的invoke()方法, 就能夠實現目標方法的加強

定義一個類ProxyFactory

該類經過兩個參數的public ProxyFactory(target,advice)構造方法構造ProxyFactory實例, 而後經過該實例的getProxy()方法獲得代理對象

 public class ProxyFactory {
	private Object target;    // 目標對象
	private Advice advice;    // 加強對象

	public ProxyFactory(Object target, Advice advice) {
		this.target = target;
		this.advice = advice;
	}

	/**
	 * 獲得代理對象
	 */
	public Object getProxy() {
		return Proxy.newProxyInstance(
				target.getClass().getClassLoader(), 
				target.getClass().getInterfaces(),
				new InvocationHandler() {
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						// 執行前置加強
						advice.before();
						// 執行目標對象的目標方法, 用result接收返回值
						Object result = method.invoke(target, args);
						// 執行後置加強
						advice.after();
						// 返回目標方法的返回值result
						return result;
					}
				});
	}
}

測試動態代理

public static void main(String[] args) {
	InterfaceImpl target = new InterfaceImpl();
	// 實現一個Advice的實例對象, 這個對象就是動態代理中加強內容
	Advice advice = new Advice() {
		@Override
		public void before() {
			System.out.println("目標方法調用以前, 執行前置加強");
		}

		@Override
		public void after() {
			System.out.println("目標方法調用以後, 執行後置加強");
		}
	};
	ProxyFactory proxyFactory = new ProxyFactory(target, advice);
	Interface proxy = (Interface) proxyFactory.getProxy();
	proxy.fun();
}

Console輸出:

方法調用以前, 執行前置加強目標方法調用方法調用以後, 執行後置加強

相關文章
相關標籤/搜索