攔截器(動態代理的升級)

之前一直在糾結攔截器中是怎麼體現動態代理的,因爲動態代理不難理解,而攔截器就是把代理工具類中的代碼放到攔截器中實現,所以綁定方法和構造方法和普通的動態代理有一點點不同。

一、編寫攔截器接口

package com.taylor.interceptor;

import java.lang.reflect.Method;

public interface Interceptor {
	/**
	 * 方法需要的4個參數
	 * 1.代理對象
	 * 2.真實對象
	 * 3.調用的方法
	 * 4.方法的參數
	 */	
	/*
	 * 1.before方法返回boolean值,它在真實對象調用之前執行,當返回值爲true,則反射真實對象的方法,若返回值
	 * 爲false,則調用around方法。
	 */
	public boolean before(Object object,Object target,Method method,Object[] args);
	
	public void after(Object object,Object target,Method method,Object[] args);

	public void around(Object object,Object target,Method method,Object[] args);
}


二、、編寫攔截器接口實現類

package com.taylor.interceptor;

import java.lang.reflect.Method;

public class MyInterceptor implements Interceptor {

	@Override
	public boolean before(Object object, Object target, Method method, Object[] args) {
		System.out.println("反射方法前邏輯");
		return true;	//不反射被代理對象原有方法
	}

	@Override
	public void after(Object object, Object target, Method method, Object[] args) {
		System.out.println("反射方法後邏輯");
	}

	@Override
	public void around(Object object, Object target, Method method, Object[] args) {
		System.out.println("取代了被代理對象的方法");
	}

}

三、編寫代理工具類

package com.taylor.interceptor;

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

public class InterceptorJdkProxy implements InvocationHandler{
	
	//把真實對象和攔截器傳遞進來
	private Object target;  //真實對象
	/*
	 * 這裏傳攔截器路徑名的原因很簡單,通過反射生成對象,而不是new
	 */
	private String InterceptorClass = null;	//這個是攔截器的路徑名
	
	//通過構造方法把值傳入
	public InterceptorJdkProxy(Object target, String interceptorClass) {
		this.target = target;
		InterceptorClass = interceptorClass;
	}
	
	
	//提供一個生成代理對象的方法,參數是真實對象和攔截器的全路徑。
	public static Object bind(Object target, String interceptorClass) {
		
		return Proxy.newProxyInstance(target.getClass().getClassLoader(), 
			target.getClass().getInterfaces(), 
			new InterceptorJdkProxy(target, interceptorClass));
		/*
		 *這裏和動態代理不同的就是第三個參數,
		 *普通動態代理的第三個參數是this,表示當前對象,因爲它調用的就是該類的方法。
		 *而這裏的第三個參數是一個代理工具類的對象,因爲它要調用的的方法是寫在了攔截器中,
		 *剛好攔截器和真實對象又可以通過構造方法傳遞進來。
		 *至於爲什麼bind()寫成static,是想通過類名直接調用,而無需生成多餘對象。
		 */
		
	}
	
	
	/*
	 * proxy:代理對象
	 * method:被調用的方法
	 * args:方法所需參數
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		//通過代理調用方法,首先進入這個方法
		if(InterceptorClass==null) {	//沒傳入攔截器,則直接反射原有方法
			return method.invoke(target, args);
		}
		Object result = null;	//返回值
		
		//通過反射生成攔截器
		Interceptor interceptor 
		= (Interceptor) Class.forName(InterceptorClass).newInstance();
		
		//調用前置方法
		if(interceptor.before(proxy, target, method, args)) {
			//反射原有方法
			result =  method.invoke(target, args);
		}else {
			//返回false執行取代方法
			interceptor.around(proxy, target, method, args);
		}
		interceptor.after(proxy, target, method, args);
		
		return result;
	}

	
	
}

四、編寫被代理對象的接口和實現類

package com.taylor.dao;

public interface HelloWorld {
	public void say();
}


package com.taylor.dao;

public class HelloWorldImpl implements HelloWorld{

	@Override
	public void say() {
		System.out.println("hello world");
	}

}

五、測試類和運行結果

package com.taylor.test;

import com.taylor.dao.HelloWorld;
import com.taylor.dao.HelloWorldImpl;
import com.taylor.interceptor.InterceptorJdkProxy;

public class TestHelloWorld {
	public static void main(String[] args) {
		//1.代理對象
		HelloWorld proxy = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImpl(),
				"com.taylor.interceptor.MyInterceptor");
		//2.通過代理對象調用方法
		proxy.say();
	}
}

*當before方法的返回值爲true時,結果是

*當before方法的返回值爲false時,結果是

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章