1. 程式人生 > >Java 動態代理(AOP實現機制)

Java 動態代理(AOP實現機制)

浪費了“黃金五年”的Java程式設計師,還有救嗎? >>>   

代理:代理顧名思義就是代理目標物件處理某些事情

正向代理:可理解成火車售賣點就是中國鐵路總公司的代理,我們把買票的業務委託給火車票售賣點,售賣點通過軟體等形式替我們向鐵總買票,然後再將車票給我們。

反向代理:例如當快遞員送快遞給某個小區的住戶,剛好客戶不在家,門衛提客戶收取快遞,等客戶空閒時就去門衛處領取快遞,這裡門衛就充當一個反向代理的角色。在網際網路訪問遠端主機的時候,我們通過不是直接訪問目標主機,而只是訪問目標主機的反向代理伺服器,工作流程大概就是我們把請求傳送給單向代理伺服器,反向代理伺服器通過解析請求然後交給內部的伺服器叢集處理,伺服器叢集將結果返回給反向代理伺服器,反向代理伺服器再將結果返回給使用者,這樣將反向代理伺服器作為一個排程者角色可以實現目標主機對外界訪問的隔離,保護目標主機,同時反向代理服務通過所有訪問的資料流量和目標主機的排程,達到負載均衡的效果,常見的反向代理伺服器Ngnix。

AOP: 面向切面程式設計,可類比J2EE中的Filter功能,Filter對請求進行過濾處理,AOP只是對介面中的方法進行過濾處理,例如當我們坐公交車刷卡,我們只是聽到滴的一聲就處理完了,整個流程我們可以分解刷卡機和磁卡建立近場通訊-->刷卡機聯網查詢金額(扣費或提示)--->滴一聲,我們做的動作只是將卡靠近刷卡機,其餘的動作是公交卡系統自動幫我們處理的,我們可以將卡靠近刷卡機這個動作看作是一個切入點(目標方法),我們自己就是被代理物件,刷卡的動作和滴一聲看作是圍著目標方法的功能擴充套件,這裡就可以裡結成一個AOP的簡單實現。常見的系統功能例如日誌功能很多都是在目標方法的前後插入需要擴充套件的方法,實現整個系統功能的擴充套件,這樣不會影響原有的程式碼結構,也可以獲取系統的全域性管理能力。

目標物件:

package com.zhiwei.dynamicProxy;

public class DefineImp implements DefineInterface{

	@Override
	public String add(String str) {
		return str+"  Python!";
	}
}

被代理介面:

package com.zhiwei.dynamicProxy;

//自定義介面
public interface DefineInterface {
	public String add(String str);
}

代理類:

package com.zhiwei.dynamicProxy;

//代理自定義介面
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class DefineProxy {

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static void main(String[] args) throws Exception {
		
		Class proxyClass=Proxy.getProxyClass(DefineInterface.class.getClassLoader(), DefineInterface.class);
		Constructor ct=proxyClass.getConstructor(InvocationHandler.class);
		
		class MyInvocationHandler implements InvocationHandler{
            //需要代理的目標物件
			DefineInterface target=new DefineImp();
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				before();
				Object result=method.invoke(target, args);
				System.out.println("目標方法返回結果:"+result);
				after();
				return result;
			}
			
		}
		DefineInterface str=(DefineInterface) ct.newInstance(new MyInvocationHandler());
		str.add("hello");
	}
	
	public static void before(){
		System.out.println("before target method is running.............");
	}
	
	public static void after(){
		System.out.println("after target method is running.............");
	}
}

結果:

分析:從結果可以看出目標方法在執行前的周邊添加了我們自定義的方法,可以將其改裝成測試程式碼執行效率的功能塊,目標方法執行前記錄開始時間,目標方法執行之後記錄結束時間,前後執行的時間差即為執行時間

Java代理物件生成的另外一種方法(本質相同):

Object obj=Proxy.newProxyInstance(
        target.getClass().getClassLoader(),  
        target.getClass().getInterfaces(),  
        new InvocationHandler() {   

[@Override](https://my.oschina.net/u/1162528)
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                advice.beforeMethod();  //前置通知
                Object obj = method.invoke(target, args);  
                advice.afterMethod(); //後置通知
                return obj;
                }
        }