Java代理模式 與 Java 動態代理

代理模式(Proxy Pattern)是 java 經常使用 設計模式 之一。其定義:爲其餘對象提供一種代理以控制對這個對象的訪問,便是:使用代理模式建立代理對象,讓代理對象控制目標對象的訪問(目標對象能夠是遠程的對象、建立開銷大的對象或須要安全控制的對象),而且能夠在不改html

變目標對象的狀況下添加一些額外的功能。java

 

UML類圖:設計模式

模式中包含的角色及其職責說明:數組

Subject:抽象主題角色,抽象主題類能夠是抽象類,也能夠是接口,是一個最普通的業務類型定義,無特殊要求。安全

RealSubject:具體主題角色,也叫被委託角色、被代理角色。是業務邏輯的具體執行者。jvm

Proxy:代理主題角色,也叫委託類、代理類。它把全部抽象主題類定義的方法給具體主題角色實現,而且在具體主題角色處理完畢先後作預處理和藹後工做。(最簡單的好比打印日誌)ide

 

代碼實現一:學習

一、Subject測試

/**
 * 抽象主題,定義主要功能
 */
public interface Subject {
   public void operate();
}

二、RealSubjectthis

/**
 * * 具體主題
 */
public class RealSubject implements Subject{

	@Override
	public void operate() {
	   System.out.println("realsubject operatestarted......");
	}
	
}

三、Proxy

/**
 * 代理類
 */
public class Proxy implements Subject{

	private Subject subject;
	
	public Proxy(Subject subject){
		this.subject = subject;
	}
	
	@Override
	public void operate() {
	    System.out.println("before operate......");
        subject.operate();
        System.out.println("after operate......");
	}

}

四、ProxyClient

**
 * 代理模式-測試客戶端
 */
public class ProxyClient {

	public static void main(String[] args) {
		 Subject subject = new RealSubject();
		 Proxy proxy = new Proxy(subject);
		 proxy.operate();
	}
	
}

運行結果:

 

Java 動態代理(轉自:http://www.cnblogs.com/xiaoluo501395377/p/3383130.html

在學習Spring的時候,咱們知道Spring主要有兩大思想,一個是IoC,另外一個就是AOP,對於IoC,依賴注入就不用多說了,而對於Spring的核心AOP來講,咱們不但要知道怎麼經過AOP來知足的咱們的功能,咱們更須要學習的是其底層是怎麼樣的一個原理,而AOP的原理就是java的動態代理機制。

在java的動態代理機制中,有兩個重要的類或接口,一個是 InvocationHandler(Interface)、另外一個則是 Proxy(Class),這一個類和接口是實現咱們動態代理所必須用到的。首先咱們先來看看java的API幫助文檔是怎麼樣對這兩個類進行描述的:

InvocationHandler:

InvocationHandler is the interface implemented by the invocation handler of a proxy instance. 

Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.

解釋:每個動態代理類都必需要實現InvocationHandler這個接口,而且每一個代理類的實例都關聯到了一個handler,當咱們經過代理對象調用一個方法的時候,這個方法的調用就會被轉發爲由InvocationHandler這個接口的 invoke 方法來進行調用。咱們來看看InvocationHandler這個接口的惟一一個方法 invoke 方法;

Object invoke(Object proxy, Method method, Object[] args) throws Throwable
Object invoke(Object proxy, Method method, Object[] args) throws Throwable

proxy:  指代咱們所代理的那個真實對象
method:  指代的是咱們所要調用真實對象的某個方法的Method對象
args:  指代的是調用真實對象某個方法時接受的參數

Proxy:

Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.

Proxy這個類的做用就是用來動態建立一個代理對象的類,它提供了許多的方法,可是咱們用的最多的就是 newProxyInstance 這個方法;

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException
Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler.
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

loader:  一個ClassLoader對象,定義了由哪一個ClassLoader對象來對生成的代理對象進行加載

interfaces:  一個Interface對象的數組,表示的是我將要給我須要代理的對象提供一組什麼接口,若是我提供了一組接口給它,那麼這個代理對象就宣稱實現了該接口(多態),這樣我就能調用這組接口中的方法了

h:  一個InvocationHandler對象,表示的是當我這個動態代理對象在調用方法的時候,會關聯到哪個InvocationHandler對象上

代碼實例:

/**
 * 代理接口
 */
public interface Subject {
	
    public void rent();
    public void hello(String str);
    
}
/**
 * 真實對象
 */
public class RealSubject implements Subject{

	@Override
	public void rent() {
		 System.out.println("I want to rent my house");
	}

	@Override
	public void hello(String str) {
		 System.out.println("hello: " + str);
	}

}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 動態代理對象
 */
public class DynamicProxy implements InvocationHandler{

	//這是咱們要代理的真實對象
    private Object subject;

    public DynamicProxy(Object subject){
    	this.subject = subject;
    }
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		
	    //在代理真實對象前咱們能夠添加一些本身的操做
        System.out.println("before rent house");
        System.out.println("Method:" + method);
       
        //當代理對象調用真實對象的方法時,其會自動的跳轉到代理對象關聯的handler對象的invoke方法來進行調用
        method.invoke(subject, args);
        
        //在代理真實對象後咱們也能夠添加一些本身的操做
        System.out.println("after rent house");
        return null;
	}

}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

/**
 * 動態代理-測試
 */
public class DynamicProxyClient {

	public static void main(String[] args) throws InstantiationException, IllegalAccessException {
		 // 咱們要代理的真實對象
         Subject realSubject = new RealSubject();
         
         // 咱們要代理哪一個真實對象,就將該對象傳進去,最後是經過該真實對象來調用其方法的
         InvocationHandler handler = new DynamicProxy(realSubject);
         
         /*
          * 經過Proxy的newProxyInstance方法來建立咱們的代理對象,咱們來看看其三個參數
          * 第一個參數 handler.getClass().getClassLoader() ,咱們這裏使用handler這個類的ClassLoader對象來加載咱們的代理對象
          * 第二個參數realSubject.getClass().getInterfaces(),咱們這裏爲代理對象提供的接口是真實對象所實行的接口,表示我要代理的是該真實對象,這樣我就能調用這組接口中的方法了
          * 第三個參數handler, 是將這個代理對象關聯到了上方的 InvocationHandler 這個對象上
          */
         Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), handler);
         System.out.println(subject.getClass().getName());
         subject.rent();
         subject.hello("world");
	}
	
}

打印結果:

說明: 一、$Proxy0 這東西,咱們看到,這個東西是由 System.out.println(subject.getClass().getName()); 這條語句打印出來的,

Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject
                .getClass().getInterfaces(), handler);可能我覺得返回的這個代理對象會是Subject類型的對象,或者是InvocationHandler的對象,結果卻不是,首先咱們解釋一下爲何咱們這裏能夠將其轉化爲Subject類型的對象?緣由就是在newProxyInstance這個方法的第二個參數上,咱們給這個代理對象提供了一組什麼接口,那麼我這個代理對象就會實現了這組接口,這個時候咱們固然能夠將這個代理對象強制類型轉化爲這組接口中的任意一個,由於這裏的接口是Subject類型,因此就能夠將其轉化爲Subject類型了。

同時咱們必定要記住,經過 Proxy.newProxyInstance 建立的代理對象是在jvm運行時動態生成的一個對象,它並非咱們的InvocationHandler類型,也不是咱們定義的那組接口的類型,而是在運行是動態生成的一個對象,而且命名方式都是這樣的形式,以$開頭,proxy爲中,最後一個數字表示對象的標號。

二、subject.rent();
subject.hello("world");

這裏是經過代理對象來調用實現的那種接口中的方法,這個時候程序就會跳轉到由這個代理對象關聯到的 handler 中的invoke方法去執行,而咱們的這個 handler 對象又接受了一個 RealSubject類型的參數,表示我要代理的就是這個真實對象,因此此時就會調用 handler 中的invoke方法去執行:

三、咱們看到,在真正經過代理對象來調用真實對象的方法的時候,咱們能夠在該方法先後添加本身的一些操做,同時咱們看到咱們的這個 method 對象是這樣的:

public abstract void com.xiaoluo.dynamicproxy.Subject.rent()

public abstract void com.xiaoluo.dynamicproxy.Subject.hello(java.lang.String)

小結:

正好就是咱們的Subject接口中的兩個方法,這也就證實了當我經過代理對象來調用方法的時候,起實際就是委託由其關聯到的 handler 對象的invoke方法中來調用,並非本身來真實調用,而是經過代理的方式來調用的,這就是咱們的java動態代理機制。

相關文章
相關標籤/搜索