1. 程式人生 > >Java動態代理的學習

Java動態代理的學習

說動態代理之前,先說一下spring對事物的管理。我們都知道Spring有兩大概念,即IOC(控制反轉)和AOP(面向切面程式設計),spring就是利用AOP的原理來實現對事物的管理,而AOP又是使用了動態代理,那具體是怎麼做的呢?簡單說明一下:

在未使用框架之前,比如使用JDBC階段,每次使物件入庫做save操作的時候,我們都需要手動的去開啟連線,提交事物,關閉連線,一萬次save操作,就要開啟一萬次連線,提交一萬次事物,關閉一萬次連線。我們就想著抽取一些共性來,將相同的操作提取出來做一些優化,相同的操作是什麼?開啟連線、關閉連線,這兩步是一樣的,對於執行儲存操作的方法肯定每次存取的值不同,不能夠抽取。那與動態代理有什麼關聯呢?動態代理一個作用就是實現對某個方法的增強,而這個方法就是save方法,我們只需要建立一個代理,讓代理每次遇到save方法的時候,就將抽取出來的開啟連線、關閉連線的操作應用到save方法上,就簡單很多,不用自己去手動控制了,”動態“,是指程式在執行時。

文章中用到的名詞解釋:被代理類和代理類的關係,類似於淘寶商家把貨物委託到淘寶平臺去銷售

被代理類:淘寶的商家

代理類:相當於“淘寶”的角色

處理程式:委託的整個流程

一、正文開始,首先我們需要建立一個統一的介面——人,正常人都需要工作,這是人的共性

package com.sinosoft.test;

public interface Person {
	void work();
}

二、程式設計師也需要工作,工作內容就比如是將資料入庫,他實現了Person的介面

package com.sinosoft.test;

/**
 * 被代理的類
 */
public class ITMan implements Person {

	@Override
	public void work() {
		System.out.println("儲存資料入庫");
	}

}

三、處理程式Handler類,裡面有一個invoke方法,可以在執行儲存操作之前自動開啟資料庫連線,執行完儲存操作以後自動關閉資料庫連線

package com.sinosoft.test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
 *請求處理類,相當於代理類要執行“被代理類所實現介面中的方法” 
 *就要先呼叫這個處理類中的處理程式
 */
public class MyHandler implements InvocationHandler {
	
	public Object obj;//定義“被代理類”的引用
	
	public MyHandler(Object obj){
		this.obj=obj;
	}
	
	/**
	 * 代理類呼叫了某個方法,就會來呼叫這個處理程式,就是下面的invoke方法,
	 * 第一個引數基本不用,第二個引數是傳過來的方法,第三個引數是傳過來方法的引數陣列
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		before();
		//反射:相當於執行“被代理類”的method方法--即傳過來的work方法
		method.invoke(obj, args);
		after();
		return null;
	}
	
	public void before(){
		System.out.println("開啟資料庫的連線");
	}
	
	public void after(){
		System.out.println("關閉資料庫的連線");
	}
	
	/**
	 *每個代理類都要有一個與之關聯的InvocationHandler,因為代理類本身並不處理方法,
	 *而是交給它的handler去處理它的invoke方法 
	 */
}

四、測試類, 目的是建立代理物件,讓代理物件去執行被代理物件的方法,實現每次入庫前自動開啟連線,入庫以後自動關閉連線。詳細解釋都在程式碼註釋裡面。

package com.sinosoft.test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/***
 * 動態代理:目的是實現方法的增強
 * 建立代理類的步驟:
 * 1、建立”被代理類“的物件
 * 2、呼叫處理程式類即Handler類的構造,來建立InvocationHandler物件
 * 3、使用java提供的proxy類的newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler handler)方法來建立代理類物件
 *
 */
public class TestProxy {
	public static void main(String[] args) {
		//建立“被代理類”的物件,需要代理誰,就建立誰
		ITMan man = new ITMan();
		//InvocationHandler是代理物件的“呼叫處理程式”的入口
		InvocationHandler handler = new MyHandler(man);
		/**
		 * 生成一個代理物件,這個物件即不是ITMan的例項,也不是MyHandler的例項,它是執行期間動態生成的那個例項,這個例項
		 * 實現了被代理類實現的介面--即ITMan.class.getInterfaces(),也就是實現了person介面,所以根據多型轉換成了
		 * Person介面型別
		 */
		//引數說明:(定義代理類的類載入器,代理類要實現的介面列表,指派方法呼叫的呼叫處理程式)
		Person proxy=(Person)Proxy.newProxyInstance(TestProxy.class.getClassLoader(), ITMan.class.getInterfaces(), handler);
		//讓代理類去呼叫handler的處理程式,即invoke
		proxy.work();
	}
	
	/**
	 * 當我們需要建立一個代理物件的時候,就使用它的newProxyInstance()方法,改方法主要是完成了兩件事情,首先是動態的建立了一個類,然後生成該類的例項
	 * 建立完這個類,首先首先得載入到記憶體裡面去,就是用這個類載入器完成的
	 */
}