mybaitsの基本的なサポート
概要:mybaitsのコア処理作業は、Executor、StatementHandler、ResultHandler、およびparamHandlerの4つのモジュールがSQL実行プロセス全体を処理することです。これらのプロセスでは、MapperStatement、SqlSource、ResultMap、およびParameterMappingのパラメータータイプオブジェクトの一部が主に構成分析のために処理されます。作業し、最終的に実際のSQL実行のプロセスを生成します。この記事では、その後の分析を容易にするためのいくつかの基本的なサポートモジュールについて主に説明します。
この記事では、主に3つの基本モジュール
1、リソースロードモジュール
2、リフレクションモジュール
3、タイプ処理モジュールを分析します。
1.リソース読み込みモジュール
リソースロードモジュールは、主にResourcesクラスとClassLoaderWrapperクラスで構成されるioパッケージの下にあります。ClassLoaderWrapperクラスは、クラスローダーを取得するためのメソッドと、クラスローダーに従ってリソースファイルとclassForNameをロードするためのメソッドを提供します。リソースは、ClassLoaderWrapperオブジェクトのパッケージです。一連の静的呼び出しメソッドを提供します。
1.ClassLoaderWrapperのコードの一部
/**
* 获取类加载器列表: 指定的,当前线程的,当前类的,system类加载器
*/
ClassLoader[] getClassLoaders(ClassLoader classLoader) {
return new ClassLoader[] { classLoader, Thread.currentThread().getContextClassLoader(),
getClass().getClassLoader(), systemClassLoader };
}
ClassLoader systemClassLoader;
{
systemClassLoader = ClassLoader.getSystemClassLoader();
}
/**
* classForName :取可用的classLoader调用Class.forName
*/
Class<?> classForName(String name, ClassLoader[] classLoader) throws ClassNotFoundException {
for (ClassLoader cl : classLoader) {
if (null != cl) {
try {
Class<?> c = Class.forName(name, true, cl);
if (null != c)
return c;
} catch (ClassNotFoundException e) {
}
}
}
throw new ClassNotFoundException("Cannot find class: " + name);
}
/**
* getResourceAsStream :取可用的classLoader调用getResourceAsStream。
*/
InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
for (ClassLoader cl : classLoader) {
if (null != cl) {
InputStream returnValue = cl.getResourceAsStream(resource);
if (null == returnValue)
returnValue = cl.getResourceAsStream("/" + resource);
if (null != returnValue)
return returnValue;
}
}
return null;
}
第二に、反射モジュール
Mybaitsは多くの場所でリフレクションを使用し、ほとんどの外部APIはMetaObjectメソッドを呼び出すことによって基になるリフレクションメソッドを呼び出します。このクラスは通常のBeanまたはコレクションをラップでき、プロパティにアクセスするためのプロパティ識別子を実装します。さらに、Reflectorクラスは、ネイティブのリフレクションメソッドを呼び出すためにリフレクションモジュールによって使用されます。また、MetaObjectの基礎となる機能操作のクラスでもあります。
1.MetaObjectテストケース
@Test
public void test1(){
Person p = new Person();
MetaObject meta = MetaObject.forObject(p, new DefaultObjectFactory(), new DefaultObjectWrapperFactory());
meta.setValue("name", "haha"); // setValue通过反射设置对象的属性
System.out.println(p.getName());
}
@Test
public void test2(){
Person p = new Person();
p.setName("haha");
List<Person> ps = new ArrayList<Person>(); // 包装lists
MetaObject meta = MetaObject.forObject(ps, new DefaultObjectFactory(), new DefaultObjectWrapperFactory());
meta.add(p); // MetaObject传入参数如果是集合类型,可以通过add给集合添加属性。
System.out.println(ps.get(0).getName());
}
@Test
public void test3(){
Person p = new Person();
p.setName("haha");
Map<String,Person> map = new HashMap<String,Person>(); // 包装map
MetaObject meta = MetaObject.forObject(map, new DefaultObjectFactory(), new DefaultObjectWrapperFactory());
meta.setValue("deer", p); // 通过setValue可以给map添加属性
System.out.println(map.get("deer").getName());
}
/**
* 属性分割符,操作内部成员对象的属性
*/
@Test
public void test4(){
Person p = new Person();
MetaObject meta = MetaObject.forObject(p, new DefaultObjectFactory(), new DefaultObjectWrapperFactory());
meta.setValue("child.name", "haha"); // 可以通过.的方式调用属性的属性
System.out.println(p.getChild().getName()); // 普通方式获取
System.out.println(meta.getValue("child.name")); // 反射方式获取值,也可以用.的方式
}
/**
* 属性分割符,操作内部成员集合对象的属性
*/
@Test
public void test5(){
Person p = new Person();
p.getChildren().add(new Person());
MetaObject meta = MetaObject.forObject(p, new DefaultObjectFactory(), new DefaultObjectWrapperFactory());
meta.setValue("children[0].name", "haha");
System.out.println(p.getChildren().get(0).getName());
System.out.println(meta.getValue("children[0].name"));
}
上記のテストから、MetaObjectは非常に使いやすく、プロパティ操作、メソッド呼び出し、インスタンス作成などのリフレクション操作が必要であり、コレクションや通常のBeanの使用と互換性があることがわかります。
2.リフレクションモジュールのクラス
MetaObject:主に外部で使用され、関数は上記で示されています。
リフレクター:基本的なリフレクションクラス。クラスのすべてのメソッド、ファイル、コンストラクターなどのリフレクションメソッドをラップし、初期化中にそれらすべてを解析します。
MetaClass:リフレクション関数をラップし、プロパティ分析のサポート、つまりprop.prop.propの形式を強化します。
PropertyTokenizer:prop.prop.propの形式のプロパティ構造のラッパー。
ObjectWrapper:MetaObjectによって作成され、MetaObjectへの参照を保持するオブジェクトラッパーインターフェイス(クラスの再帰呼び出しに使用)。4つの実装があります。1つはBaseWrapper、1つはBeanWrapper、1つはCollectionWrapper、もう1つはMapWrapperです。
3、リフレクター
a)最初に主なプロパティとコンストラクターを見てください
private Class<?> type;
private String[] readablePropertyNames = EMPTY_STRING_ARRAY; // 可读属性名数组
private String[] writeablePropertyNames = EMPTY_STRING_ARRAY; // 可写属性名数组
private Map<String, Invoker> setMethods = new HashMap<String, Invoker>(); // set方法
private Map<String, Invoker> getMethods = new HashMap<String, Invoker>(); // get方法
private Map<String, Class<?>> setTypes = new HashMap<String, Class<?>>(); // set类型
private Map<String, Class<?>> getTypes = new HashMap<String, Class<?>>(); // get类型
private Constructor<?> defaultConstructor; // 默认构造函数
private Reflector(Class<?> clazz) {
type = clazz; // 指定类型
addDefaultConstructor(clazz); //解析默认构造函数
addGetMethods(clazz); // 解析所有get方法
addSetMethods(clazz); // 解析所有set方法
addFields(clazz); // 所有字段
readablePropertyNames = getMethods.keySet().toArray(new String[getMethods.keySet().size()]); // 可读属性名的集合
writeablePropertyNames = setMethods.keySet().toArray(new String[setMethods.keySet().size()]); // 可写属性名的集合
}
Reflectorはコンストラクターを作成するときに、クラスのすべてのメソッド、フィールド、コンストラクター、およびその他の情報を解析します。これらの情報は、直接または後で判断するために使用できます。追加メソッドを解析するプロセスを見てみましょう。
b)addGetMethodsメソッド
private void addGetMethods(Class<?> cls) {
Map<String, List<Method>> conflictingGetters = new HashMap<String, List<Method>>(); // 用于解决多个method冲突用
Method[] methods = getClassMethods(cls); // 得到本类父类的所有声明方法,踢出了桥接方法
for (Method method : methods) {
String name = method.getName();
if (name.startsWith("get") && name.length() > 3) { // 是get方法
if (method.getParameterTypes().length == 0) { // 并且没有参数
name = PropertyNamer.methodToProperty(name); // 方法名称变成属性名
addMethodConflict(conflictingGetters, name, method); // 添加到处理冲突的map中,因为一个属性名可能对应多个方法
}
} else if (name.startsWith("is") && name.length() > 2) { // 是is方法
if (method.getParameterTypes().length == 0) {
name = PropertyNamer.methodToProperty(name);
addMethodConflict(conflictingGetters, name, method);
}
}
}
resolveGetterConflicts(conflictingGetters); // 处理冲突
}
private void resolveGetterConflicts(Map<String, List<Method>> conflictingGetters) {
for (String propName : conflictingGetters.keySet()) {
List<Method> getters = conflictingGetters.get(propName);
Iterator<Method> iterator = getters.iterator();
Method firstMethod = iterator.next();
if (getters.size() == 1) { // 冲突只有1个method直接添加
addGetMethod(propName, firstMethod);
} else {
Method getter = firstMethod;
Class<?> getterType = firstMethod.getReturnType(); // 上次遍历方法的返回类型
while (iterator.hasNext()) {
Method method = iterator.next();
Class<?> methodType = method.getReturnType();
if (methodType.equals(getterType)) {
throw new ReflectionException(""); // 虽然是合法重载,但是属性类型不明确,不符合规范。
} else if (methodType.isAssignableFrom(getterType)) { // 返回类型是上次的父类型,更不明确,不使用。
// OK getter type is descendant
} else if (getterType.isAssignableFrom(methodType)) { // 如果当前遍历方法返回类型比上次返回类型更具体。
getter = method; // 指定此方法为当前遍历方法
getterType = methodType; // 指定成此类型
} else {
throw new ReflectionException();
}
}
addGetMethod(propName, getter);
}
}
}
4、メタクラス
MetaClassはReflectorのラッパーであり、prop.propプロパティアクセサーのリフレクションサポートが強化されています。
5、PropertyTokenizer
PropertyTokenizerの主な機能は、prop.propプロパティシンボルフォームをオブジェクトとして表すことです。
たとえば、list [0] .item [2] .idは最終的にTempObj [name = list、IndexedName = list [0]、indexに解決されます。 = 0、子= item [2] .id]のオブジェクト
コードは次のように実装されます。
public PropertyTokenizer(String fullname) {
int delim = fullname.indexOf('.'); // 对象符
if (delim > -1) { // 有
name = fullname.substring(0, delim); // name第一节点
children = fullname.substring(delim + 1); // children为剩余的
} else {
name = fullname;
children = null;
}
indexedName = name; // 属性名称有可能带[]的形式
delim = name.indexOf('[');
if (delim > -1) { // 如果有[
index = name.substring(delim + 1, name.length() - 1); // index为数组属性中角标
name = name.substring(0, delim); // name要去除[]
}
}
6、メタオブジェクト
a)最初にメタオブジェクトのコンストラクターを見てください
private Object originalObject; // 原对象
private ObjectWrapper objectWrapper; // 对象包装
private ObjectFactory objectFactory; // 对象创建工厂
private ObjectWrapperFactory objectWrapperFactory; // 忽略
private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory) {
this.originalObject = object;
this.objectFactory = objectFactory;
this.objectWrapperFactory = objectWrapperFactory;
if (object instanceof ObjectWrapper) {
this.objectWrapper = (ObjectWrapper) object;
} else if (objectWrapperFactory.hasWrapperFor(object)) { // 空实现
this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
} else if (object instanceof Map) { // MapWrapper的包装
this.objectWrapper = new MapWrapper(this, (Map) object);
} else if (object instanceof Collection) { // Collection的包装
this.objectWrapper = new CollectionWrapper(this, (Collection) object);
} else { // bean的包装
this.objectWrapper = new BeanWrapper(this, object); // 如果是javabean,就包装成这个,并且传递this,是为了伪递归调用本对象的getValue等方法。
}
}
MetaObjectのコンストラクターからわかるように、MetaObjectは、ラップするオブジェクトのタイプに応じて対応するObjectWrapperを作成します。MapWrapperとCollectionWrapperはいくつかのコンテナーメソッドの実装であり、BeanWrapperはリフレクションメソッドの実装です。各BeanWrapperは、それを作成したMetaObjectへの参照を保持し、内部でMetaClassを呼び出してリフレクション操作を実装します。
次のsetValueメソッドを分析します。
public void setValue(String name, Object value) {
PropertyTokenizer prop = new PropertyTokenizer(name); // 包装属性访问符成为对象
if (prop.hasNext()) { // 判断是否有子属性
// 这里反射获取此子属性的值,这里内部调用getValue,但是只有单个name,因此不会递归获取子属性
// 获取子属性后,会包装成新的MetaObject
MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
if (metaValue == SystemMetaObject.NULL_META_OBJECT) { // value空值包装成的默认空的MetaObject
if (value == null && prop.getChildren() != null) {
return;
} else {
// 实例化此子属性,并且反射设置到此对象中,另外包装成MetaObject
metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory);
}
}
// 当前name属性因为有子属性需要设置,本name的属性已经实例化,并且本name属性也已经包装成了MetaValue,就可以伪递归SetValue
metaValue.setValue(prop.getChildren(), value);
} else { // 只设置一级属性的值。
objectWrapper.set(prop, value);
}
}
public MetaObject metaObjectForProperty(String name) {
Object value = getValue(name); // 因为name是个单节点的属性,getValue不会递归了。
return MetaObject.forObject(value, objectFactory, objectWrapperFactory); // value就算空值也会进行包装
}
上記は、メタオブジェクトリフレクションを介してオブジェクトシンボルフォーム属性文字列を設定する方法です。このクラスの関数は、上記のすべてのクラスの関数を統合します。
MetaObject実装ロジックテキストの説明:
オブジェクトはコレクションまたはjavaBeanの場合があります。属性シンボルを介してアクセスする場合は、最初に属性シンボルにオブジェクトを設定し、次にオブジェクトがコレクションであるかjavabeanであるかに応じて異なるObjectWrappersをインスタンス化します。 。ObjectWrapperは、コレクション内のプロパティ、マルチレベルプロパティへのリフレクションまたはアクセスを担当し、各レベルを新しいMetaObjectにパッケージ化することで疑似再帰操作を実行します。再帰的に渡される小道具は2番目のレベルの後にあります。
3、タイプ処理モジュール
1.基本的な紹介。
型処理の最上位インターフェースはTypeHandlerであり、そのインターフェース形式は次のとおりです。
类型处理的顶级接口是TypeHandler,它的接口形式如下:
public interface TypeHandler<T> {
/**
* 填充PreparedStatement的参数
*/
void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
/**
* 得到结果,根据别名
*/
T getResult(ResultSet rs, String columnName) throws SQLException;
/**
* 得到结果,根据列角标
*/
T getResult(ResultSet rs, int columnIndex) throws SQLException;
/**
* 从CallableStatement得到结果。
*/
T getResult(CallableStatement cs, int columnIndex) throws SQLException;
}
その主な機能は、ParameterHandlerとResultetHandlerがプリペアド・ステートメントの暗黙のパラメーターを処理することと、結果セット処理の型変換メソッドです。そして、その具体的な実現は、タイプごとに異なる処理の実現です。いくつかを選んで見てみましょう。
public class IntegerTypeHandler extends BaseTypeHandler<Integer> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Integer parameter, JdbcType jdbcType)
throws SQLException {
ps.setInt(i, parameter);
}
@Override
public Integer getNullableResult(ResultSet rs, String columnName)
throws SQLException {
return rs.getInt(columnName);
}
@Override
public Integer getNullableResult(ResultSet rs, int columnIndex)
throws SQLException {
return rs.getInt(columnIndex);
}
@Override
public Integer getNullableResult(CallableStatement cs, int columnIndex)
throws SQLException {
return cs.getInt(columnIndex);
}
}
上記からわかるように、各タイプのタイプ処理の実装は比較的単純です。重要なのは、パラメーターマッピングなど、このタイプのプロセッサーを使用する理由です。どのタイプのプロセッサーが必要ですか。これは、パラメータの実際のタイプに従ってタイププロセッサを見つけることです。同様に、戻り値の処理は、戻り値のタイプまたはresultMapのタイプ構成に基づいて、特定のタイプのプロセッサを見つけることができます。特定のプロセスはチェックされません。 、タイプのみを確認します。プロセッサはどのように登録され、どこに登録されますか?
2.
TypeHandlerの登録TypeHandlerは、ConfigurnのTypeHandlerRegistryインスタンスに登録されます。
TypeHandlerRegistryのプロパティ
// JDBCType对应的处理器映射
private final Map<JdbcType, TypeHandler<?>> JDBC_TYPE_HANDLER_MAP = new EnumMap<JdbcType, TypeHandler<?>>(JdbcType.class);
// java类型对应的处理器映射 (一个java类型可以注册多个jdbc类型,默认null的key注册的是默认的处理器)
private final Map<Type, Map<JdbcType, TypeHandler<?>>> TYPE_HANDLER_MAP = new HashMap<Type, Map<JdbcType, TypeHandler<?>>>();
// 类型处理器clas和实例的映射
private final Map<Class<?>, TypeHandler<?>> ALL_TYPE_HANDLERS_MAP = new HashMap<Class<?>, TypeHandler<?>>();
実際の登録方法
private void register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler) {
if (javaType != null) {
Map<JdbcType, TypeHandler<?>> map = TYPE_HANDLER_MAP.get(javaType);
if (map == null) { // 创建子map
map = new HashMap<JdbcType, TypeHandler<?>>();
TYPE_HANDLER_MAP.put(javaType, map);
}
map.put(jdbcType, handler); // put进子map
if (reversePrimitiveMap.containsKey(javaType)) { // 同时注册元素类型
register(reversePrimitiveMap.get(javaType), jdbcType, handler);
}
}
ALL_TYPE_HANDLERS_MAP.put(handler.getClass(), handler);
}
3.mybaitsタイプのプロセッサの実際の使用。
終わり!