Mybatis技術內幕(2.3.3):反射模組-Invoker

失控的阿甘發表於2019-03-18

基於Mybatis-3.5.0版本

1.0 Invoker執行器

org.apache.ibatis.reflection.invoker.Invoker執行器介面,這裡主要是為了統一getter方法、setter方法和Field個get和set執行時的差異,使用了物件的介面卡模式。程式碼和類圖如下:

Mybatis技術內幕(2.3.3):反射模組-Invoker

/**
 * 執行器介面:為了統一getter方法、setter方法和Field個get和set執行時的差異
 * 物件的介面卡模式
 * @author Clinton Begin
 */
public interface Invoker {
	/**
     * 執行呼叫
     * 主要用於執行:getter方法、setter方法和Field個get和set
     * @param target 目標
     * @param args 引數
     * @return 結果
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
	Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException;

	/**
     * @return 類
     * 差異:
     * 1.getter方法 返回返回型別
     * 2.setter方法 返回引數型別
     * 3.Field返回自身的型別
     */
	Class<?> getType();
}
複製程式碼

程式碼都比較簡單,就直接上程式碼了

2.0 GetFieldInvoker

/**
 * Field get屬性執行器
 * @author Clinton Begin
 */
public class GetFieldInvoker implements Invoker {
	//Field 物件 即被適配者
	private final Field field;

	public GetFieldInvoker(Field field) {
		this.field = field;
	}

	/**
	 * 獲取 target Field的屬性值
	 * 如果Field不可訪問 (訪問許可權不夠),則設定Accessible 強制訪問
	 */
	@Override
	public Object invoke(Object target, Object[] args) throws IllegalAccessException {
		try {
			return field.get(target);
		} catch (IllegalAccessException e) {
			if (Reflector.canControlMemberAccessible()) {
				field.setAccessible(true);
				return field.get(target);
			} else {
				throw e;
			}
		}
	}

	/**
	 * 返回Field型別
	 */
	@Override
	public Class<?> getType() {
		return field.getType();
	}
}
複製程式碼

2.1 SetFieldInvoker

/**
 * Field set屬性執行器
 * @author Clinton Begin
 */
public class SetFieldInvoker implements Invoker {
	// Field 物件 即被適配者
	private final Field field;

	public SetFieldInvoker(Field field) {
		this.field = field;
	}

	/**
	 * 設定 target Field的屬性值
	 * 如果Field不可訪問 (訪問許可權不夠),則設定Accessible 強制訪問
	 */
	@Override
	public Object invoke(Object target, Object[] args) throws IllegalAccessException {
		try {
			field.set(target, args[0]);
		} catch (IllegalAccessException e) {
			if (Reflector.canControlMemberAccessible()) {
				field.setAccessible(true);
				field.set(target, args[0]);
			} else {
				throw e;
			}
		}
		return null;
	}

	/**
	 * 返回Field型別
	 */
	@Override
	public Class<?> getType() {
		return field.getType();
	}
}
複製程式碼

2.2 MethodInvoker

/**
 * getter或setter方法執行器
 * @author Clinton Begin
 */
public class MethodInvoker implements Invoker {
	/**
	 * getter方法 返回返回型別
     * setter方法 返回引數型別
	 */
	private final Class<?> type;
	/**
	 * Method物件 即被適配者
	 */
	private final Method method;

	public MethodInvoker(Method method) {
		this.method = method;

		if (method.getParameterTypes().length == 1) {
			type = method.getParameterTypes()[0];
		} else {
			type = method.getReturnType();
		}
	}

	/**
	 * 執行method物件對應的方法
	 * 如果method不可訪問 (訪問許可權不夠),則設定Accessible 強制訪問
	 */
	@Override
	public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {
		try {
			return method.invoke(target, args);
		} catch (IllegalAccessException e) {
			if (Reflector.canControlMemberAccessible()) {
				method.setAccessible(true);
				return method.invoke(target, args);
			} else {
				throw e;
			}
		}
	}

	@Override
	public Class<?> getType() {
		return type;
	}
}
複製程式碼

3.0 介面卡模式

介面卡模式下面這篇文章介紹的還不錯:

《JAVA與模式》之介面卡模式

4.0 總結

大家在實際的開發中也可以巧用一些設計模式,使專案的程式碼更加健壯。例如Mybatis反射模組中,如果這裡不使用介面卡模式,那在Reflector中快取setter和getter的元資訊時就不得不使用4個Map分別取快取:getter方法,setter方法、Field-get和Field-set,並且在實際的使用時還要去做if判斷

失控的阿甘,樂於分享,記錄點滴

相關文章