JDK 動態代理

JDK 代理

  java中的代理是指某個對象的一個替代者,該替代者暫時擔任了被代理對象的職責,代理對象包含了原始對象的全部方法,並且還有可能會附加一些額外的方法。代理對象就是在不破壞原始對象的前提下發揮和原始對象相同甚至更多的功能,Java中的代理分爲靜態代理和動態代理兩種。java

靜態代理:

    在爲某個對象生成代理對象以前,就已經知道代理對象要實現的功能或者發揮的做用,那麼只須要從新寫一個代理類,該類和原始類實現了相同的接口,而後在代理類的方法中加入某些附加的處理操做,這種代理類對象的行爲是肯定的,因此稱爲靜態代理。spring

public interface Eatable{
     void eat();
}
class Person implements Eatable{
     public void eat(){
          System.out.println("吃飯");
     }
}
class ProxyPerson implements Eatable{
     private Person person;
     public ProxyPerson(Person person){
          this.person = person;
     }
     public void eat(){
          System.out.println("吃飯以前先要洗手!");
          person.eat();
     }
}

   上述代碼中,先定義了一個接口Eatable.該接口中有一個eat方法,而後有一個原始類Person實現了該接口,可是此時咱們不想用Person對象的eat()方法,由於這種Person在吃飯的時候老是不洗手,這種Person太噁心了!很明確,咱們須要一個洗手的Person,這就出現了ProxyPerson,ProxyPerson中組合了Person,ProxyPerson的eat方法中先執行附加的操做,而後在執行真正的eat操做。這就是靜態代理。ide

     可是有一個問題,假如咱們又要在吃飯以後洗碗,那又得從新寫一個ProxyPerson2,包含一個eat方法,該方法先吃飯,而後在洗碗,若是又出現一個需求,咱們要的這個Person既要能飯前洗手,還能飯後洗碗,那怎麼辦?再寫一個ProxyPerson3?這樣下去,隨着咱們的需求愈來愈多,咱們的類就會膨脹到爆。這時候動態代理就發揮做用了。函數

動態代理:

    動態代理跟靜態代理的區別是代理類不是開發者用源代碼定義出的,而是經過java的反射機制在程序運行期生成的。jdk動態代理的主要靠InvocationHandler藉口和Proxy類配合來實現的。JDK動態代理的被代理對象必定要有接口,經過動態生成接口實現類而後經過組合的方式實如今方法先後do something.性能

InvocationHandler接口主要方法:學習

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

   經過實現該接口實現定義的橫切邏輯,並經過反射機制調用目標類的代碼,動態的將橫切邏輯和業務邏輯編織在一塊兒。測試

Proxy類主要屬性和方法: this

public class Proxy {
    protected InvocationHandler h;
 
    private Proxy() {
    }
 
    protected Proxy(InvocationHandler h) {
        this.h = h;
    }
 
    public static Class<?> getProxyClass(ClassLoader loader,Class<?>... interfaces) throws IllegalArgumentException {
 
    }
 
    public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException {
 
    }
}

    利用InvocationHandler動態建立一個符合某一接口的實例,生成目標類的代理對象。spa

代碼實例爲一個方法性能監視:線程

    接口:

package com.qding.agency.service;

public interface UserService {

	public int addUser(String name);
	
	public void delUser(Long userId);
}

  接口實現類:

package com.qding.agency.service.impl;

import com.qding.agency.service.UserService;

public class UserServiceImpl implements UserService {

	@Override
	public int addUser(String name) {
		System.out.println("新增用戶:"+name);
		try {
			Thread.currentThread().sleep(20);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 1;
	}

	@Override
	public void delUser(Long userId) {
		System.out.println("刪除用戶:"+userId);
		try {
			Thread.currentThread().sleep(40);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
}

代理處理類:

package com.qding.agency.hander;

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

import com.qding.agency.monitor.PerformanceMonitor;

public class PerformanceHander implements InvocationHandler {
	
	private Object target;
	
	public PerformanceHander(Object target){
		this.target=target;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		
		PerformanceMonitor.begin(target.getClass().getName()+"."+method.getName());
		Object object = method.invoke(target, args);
		PerformanceMonitor.end();
		return object;
	}

}

監視類:

package com.qding.agency.monitor;

public class PerformanceMonitor {
	
	//經過一個Threadlocal保存調用線程的相關的性能監視信息
	private static ThreadLocal<MethodPerformance> performanceRecord = new ThreadLocal<MethodPerformance>();
	
	public static void begin(String method){
		System.out.println("begin Monitor"+method);
		MethodPerformance mp =new MethodPerformance(method);
		performanceRecord.set(mp);
	}
	
	public static void end(){
		System.out.println("end Monitor....");
		MethodPerformance mp =performanceRecord.get();
		mp.printPerformance();
	}

}

方法耗時計時:

package com.qding.agency.monitor;

public class MethodPerformance {

	private long begin;

	private long end;

	private String serviceMethod;

	public MethodPerformance(String serviceMethod) {
		this.serviceMethod = serviceMethod;
		// 記錄方法開始時間
		this.begin = System.currentTimeMillis();
	}

	public void printPerformance() {
		// 計算方法耗時並打印
		end = System.currentTimeMillis();
		long elapsed = end - begin;
		System.out.println(serviceMethod + "花費" + elapsed + "毫秒");
	}

}

測試類:

package com.qding.agency.test;

import java.lang.reflect.Proxy;

import com.qding.agency.hander.PerformanceHander;
import com.qding.agency.service.UserService;
import com.qding.agency.service.impl.UserServiceImpl;

public class TestUserPerformanceinfo {

	public static void main(String[] args) {

		UserService userservice = new UserServiceImpl();

		PerformanceHander ph = new PerformanceHander(userservice);

		UserService proxy = (UserService) Proxy.newProxyInstance(userservice.getClass()
				.getClassLoader(), userservice.getClass().getInterfaces(), ph);
		proxy.addUser("張三");
		proxy.delUser(1l);
	}

}

運行結果:

begin Monitorcom.qding.agency.service.impl.UserServiceImpl.addUser
新增用戶:張三
end Monitor....
com.qding.agency.service.impl.UserServiceImpl.addUser花費31毫秒
begin Monitorcom.qding.agency.service.impl.UserServiceImpl.delUser
刪除用戶:1
end Monitor....
com.qding.agency.service.impl.UserServiceImpl.delUser花費47毫秒

以上代碼小實例是在學習spring AOP時看到的,對於理解動態代理有點小繞,其實jdk動態代理就是要有一個接口,而後接口實現類,最重要的是代理處理類要實現InvocationHandler 接口,而後在invoke方法中寫些 do something 

       beofor do something

    Object result = paramMethod.invoke(object, paramArrayOfObject);

        after do something


在使用時,建立須要被代理的目標類。將目標類放入代理處理類,建立代理類實例,調用代理實例。

       

//但願被代理的目標類
UserService userservice = new UserServiceImpl();
//將目標類放入代理處理類中
PerformanceHander ph = new PerformanceHander(userservice);
//建立代理實例
UserService proxy = (UserService) Proxy.newProxyInstance(userservice.getClass().getClassLoader(), userservice.getClass().getInterfaces(), ph);
//調用代理實例		
proxy.addUser("張三");
proxy.delUser(1l);


proxy在運行時實際上是JDK動態生成的一個代理類($proxy0)

(1)newProxyInstance方法調用getProxyClass方法,返回代理類的class:$Proxy0類。同時,java還讓這個動態生成的$Proxy0類實現了newProxyInstance方法接收的全部接口,並繼承了Proxy類。 獲得的實際上是一個類名叫$Proxy0 extends Proxy implements counter.getClass().getInterfaces()的類

(2)實例化這個動態生成的$Proxy0類的一個實例。由於$Proxy0類也繼承了Proxy類,因此能夠調用Proxy類的protected Proxy(InvocationHandler h)構造函數,並將咱們定義的InvocationHandler子類的一個實例做爲參數。

(3)經過第二步驟,咱們擁有了一個代理類的實例,而且這個代理類的實例包含一個InvocationHandler實例。將該代理類實例返回,而且強制類型轉換爲接口類型:UserService。

(4)調用代理類實例的addUser()方法。在調用add方法時,實際上是調用了代理類實例包含的那個InvocationHandler實例的invoke方法,即super.h.invoke(this, , )。

JDK動態代理只能對實現了接口的類進行代理,這也是其侷限性之一.

相關文章
相關標籤/搜索