MyBatisMyBatis源码解析(九)——Type类型模块之类型处理器注册器(TypeHandlerRegistry)

原创作品,可以转载,但是要标注出处地址:http://www.cnblogs.com/V1haoge/p/6709157.html

1、回顾

  上亦然篇研究之凡种类别名注册器TypeAliasRegister,它根本用于将基本项目及用户从定义之档次进行别名注册,将别名及其对应类类型保存于一个HashMap中,方便存取,是映射器映射功能实现之功底,本篇所研究之门类处理器注册器TypeHandlerReister是因此来统筹管理型处理器的,类型处理器是真的用于开展java类型与数据库类型映射的工具。

  这无异首我们还是根本研究型处理器的注册器,有关具体项目处理器的钻研放到之后进展。

2、类型处理器

  为了研究项目处理器注册器,我们要针对项目处理器有必然之基本功与认得,这里大概介绍一下,具体内容可当下同样篇。

  类型处理器简单点说即使是用于拍卖javaType与jdbcType之间类型转换用底微机,MyBatis针对诸多Java类型与数据库类型进行了相当处理。

  它主要用于映射器配置文件之做事,在经项目别名注册器获取项目别名代表的项目之后,就可以下得之花色通过品种处理器注册器来获得那个相应的JdbcType和相应之种处理器。

  由此可见每个类别处理器都针对个别只项目,一个Java类型,一个数据库类型。而项目处理器的意就是进行二者之间的相当、对应、转换。

3、类型处理器注册器

  类型处理器注册器既能够成功项目处理器的注册功能,同时为会针对品种处理器进行统筹管理,其里面定义了集来拓展路处理器的存取,同时定义了存取方法。

1   private final Map<JdbcType, TypeHandler<?>> JDBC_TYPE_HANDLER_MAP = new EnumMap<JdbcType, TypeHandler<?>>(JdbcType.class);
2   private final Map<Type, Map<JdbcType, TypeHandler<?>>> TYPE_HANDLER_MAP = new HashMap<Type, Map<JdbcType, TypeHandler<?>>>();
3   private final Map<Class<?>, TypeHandler<?>> ALL_TYPE_HANDLERS_MAP = new HashMap<Class<?>, TypeHandler<?>>();

  以上是TypeHandlerRegister中定义之老三只Map集合,这三独集是为此来保存类型处理器的登记信息的。

  第一种:JDBC_TYPE_HANDLER_MAP,这是一个枚举Map集合,其内部是为JdbcType枚举类中枚举值为键创建的一模一样种集合,这种集先天存在键(枚举值),它是因数据库类型也键来保存类型处理器,亦将类型处理器注册及对应的数据库类型上。

  第二种:TYPE_HANDLER_MAP,这是一个前套Map集合,内层集合是以数据库类型为键保存处理器,外层集合为以Java类型来保存对应之数据库类型及其处理器,这个集将三者关系起来,是真正进展三者对诺涉及相当的聚众。

  第三种:ALL_TYPE_HANDLERS_MAP,这个集中保留在所有的品类处理器,是坐档处理器的类类型为键值保存的,它可统筹有的品种处理器(带有统计的效果)。

3.1 基础项目处理器

  于创造项目处理器注册器的当儿,在其不论是参构造器中会展开基础项目处理器的登记,这些注册包括三种植艺术,一种植是将以JavaType为键的保留方法,一栽是因JdbcTye为键的保留方法,还有一样种就是以JavaType与JdbcType为键的保留方法,这最后一种植保存方法是千篇一律栽嵌套的Map集合,前面的少种植才是简单的Map集合。

  下面将欠管参构造器源码罗列:

 1   //构造函数里注册系统内置的类型处理器
 2   public TypeHandlerRegistry() {    
 3     //以下是为多个类型注册到同一个handler
 4     register(Boolean.class, new BooleanTypeHandler());
 5     register(boolean.class, new BooleanTypeHandler());
 6     register(JdbcType.BOOLEAN, new BooleanTypeHandler());
 7     register(JdbcType.BIT, new BooleanTypeHandler());
 8 
 9     register(Byte.class, new ByteTypeHandler());
10     register(byte.class, new ByteTypeHandler());
11     register(JdbcType.TINYINT, new ByteTypeHandler());
12 
13     register(Short.class, new ShortTypeHandler());
14     register(short.class, new ShortTypeHandler());
15     register(JdbcType.SMALLINT, new ShortTypeHandler());
16 
17     register(Integer.class, new IntegerTypeHandler());
18     register(int.class, new IntegerTypeHandler());
19     register(JdbcType.INTEGER, new IntegerTypeHandler());
20 
21     register(Long.class, new LongTypeHandler());
22     register(long.class, new LongTypeHandler());
23 
24     register(Float.class, new FloatTypeHandler());
25     register(float.class, new FloatTypeHandler());
26     register(JdbcType.FLOAT, new FloatTypeHandler());
27 
28     register(Double.class, new DoubleTypeHandler());
29     register(double.class, new DoubleTypeHandler());
30     register(JdbcType.DOUBLE, new DoubleTypeHandler());
31 
32       //以下是为同一个类型的多种变种注册到多个不同的handler
33     register(String.class, new StringTypeHandler());
34     register(String.class, JdbcType.CHAR, new StringTypeHandler());
35     register(String.class, JdbcType.CLOB, new ClobTypeHandler());
36     register(String.class, JdbcType.VARCHAR, new StringTypeHandler());
37     register(String.class, JdbcType.LONGVARCHAR, new ClobTypeHandler());
38     register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());
39     register(String.class, JdbcType.NCHAR, new NStringTypeHandler());
40     register(String.class, JdbcType.NCLOB, new NClobTypeHandler());
41     register(JdbcType.CHAR, new StringTypeHandler());
42     register(JdbcType.VARCHAR, new StringTypeHandler());
43     register(JdbcType.CLOB, new ClobTypeHandler());
44     register(JdbcType.LONGVARCHAR, new ClobTypeHandler());
45     register(JdbcType.NVARCHAR, new NStringTypeHandler());
46     register(JdbcType.NCHAR, new NStringTypeHandler());
47     register(JdbcType.NCLOB, new NClobTypeHandler());
48 
49     register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());
50     register(JdbcType.ARRAY, new ArrayTypeHandler());
51 
52     register(BigInteger.class, new BigIntegerTypeHandler());
53     register(JdbcType.BIGINT, new LongTypeHandler());
54 
55     register(BigDecimal.class, new BigDecimalTypeHandler());
56     register(JdbcType.REAL, new BigDecimalTypeHandler());
57     register(JdbcType.DECIMAL, new BigDecimalTypeHandler());
58     register(JdbcType.NUMERIC, new BigDecimalTypeHandler());
59 
60     register(Byte[].class, new ByteObjectArrayTypeHandler());
61     register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());
62     register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());
63     register(byte[].class, new ByteArrayTypeHandler());
64     register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());
65     register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());
66     register(JdbcType.LONGVARBINARY, new BlobTypeHandler());
67     register(JdbcType.BLOB, new BlobTypeHandler());
68 
69     register(Object.class, UNKNOWN_TYPE_HANDLER);
70     register(Object.class, JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
71     register(JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
72 
73     register(Date.class, new DateTypeHandler());
74     register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());
75     register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());
76     register(JdbcType.TIMESTAMP, new DateTypeHandler());
77     register(JdbcType.DATE, new DateOnlyTypeHandler());
78     register(JdbcType.TIME, new TimeOnlyTypeHandler());
79 
80     register(java.sql.Date.class, new SqlDateTypeHandler());
81     register(java.sql.Time.class, new SqlTimeTypeHandler());
82     register(java.sql.Timestamp.class, new SqlTimestampTypeHandler());
83 
84     // issue #273
85     register(Character.class, new CharacterTypeHandler());
86     register(char.class, new CharacterTypeHandler());
87   }

  通过源码可以窥见:MyBatis内置注册的品种处理器很是完美,几乎囊括了独具常用的种,所以一般情形下我们直接动用内置的路处理器进行项目处理即可。

3.1.1
针对JavaType,MyBatis内置注册了转档:

序号

javaType

JdbcType

TypeHandler

入口

说明

1

Boolean.class

null

BooleanTypeHandler

入口2

 

2

boolean.class

null

BooleanTypeHandler

 

3

Byte.class

null

ByteTypeHandler

 

4

byte.class

null

ByteTypeHandler

 

5

Short.class

null

ShortTypeHandler

 

6

short.class

null

ShortTypeHandler

 

7

Integer.class

null

IntegerTypeHandler

 

8

int.class

null

IntegerTypeHandler

 

9

Long.class

null

LongTypeHandler

 

10

long.class

null

LongTypeHandler

 

11

Float.class

null

FloatTypeHandler

 

12

float.class

null

FloatTypeHandler

 

13

Double.class

null

DoubleTypeHandler

 

14

double.class

null

DoubleTypeHandler

 

15

String.class

null

StringTypeHandler

 

16

BigDecimal.class

null

BigDecimalTypeHandler

 

17

BigInteger.class

null

BigIntegerTypeHandler

 

18

Byte[].class

null

ByteObjectArrayTypeHandler

 

19

byte[].class

null

ByteArrayTypeHandler

 

20

Object.class

null

UNKNOWN_TYPE_HANDLER

 

21

Date.class

null

DateTypeHandler

 

22

java.sql.Date.class

null

SqlDateTypeHandler

 

23

java.sql.Time.class

null

SqlTimeTypeHandler

 

24

Character.class

null

CharacterTypeHandler

 

25

char.class

null

CharacterTypeHandler

 

26

java.sql.Timestamp.class

null

SqlTimestampTypeHandler

 

3.1.2
针对JdbcType,MyBatis内置注册了一晃种类:

序号

javaType

JdbcType

TypeHandler

入口

说明

1

 

JdbcType.BOOLEAN

BooleanTypeHandler

入口1

 

2

 

JdbcType.BIT

BooleanTypeHandler

 

3

 

JdbcType.TINYINT

ByteTypeHandler

 

4

 

JdbcType.SMALLINT

ShortTypeHandler

 

5

 

JdbcType.INTEGER

IntegerTypeHandler

 

6

 

JdbcType.FLOAT

FloatTypeHandler

 

7

 

JdbcType.DOUBLE

DoubleTypeHandler

 

8

 

JdbcType.CHAR

StringTypeHandler

 

9

 

JdbcType.VARCHAR

StringTypeHandler

 

10

 

JdbcType.CLOB

ClobTypeHandler

 

11

 

JdbcType.LONGVARCHAR

ClobTypeHandler

 

12

 

JdbcType.NVARCHAR

NStringTypeHandler

 

13

 

JdbcType.NCHAR

NStringTypeHandler

 

14

 

JdbcType.NCLOB

NClobTypeHandler

 

15

 

dbcType.ARRAY

ArrayTypeHandler

 

16

 

JdbcType.BIGINT

LongTypeHandler

 

17

 

JdbcType.REAL

BigDecimalTypeHandler

 

18

 

JdbcType.DECIMAL

BigDecimalTypeHandler

 

19

 

JdbcType.NUMERIC

BigDecimalTypeHandler

 

20

 

JdbcType.LONGVARBINARY

BlobTypeHandler

 

21

 

JdbcType.BLOB

BlobTypeHandler

 

22

 

JdbcType.OTHER

UNKNOWN_TYPE_HANDLER

 

23

 

JdbcType.TIMESTAMP

DateTypeHandler

 

24

 

JdbcType.DATE

DateOnlyTypeHandler

 

25

 

JdbcType.TIME

TimeOnlyTypeHandler

 

3.1.3
针对JdbcType和JavaType,MyBatis内置注册了瞬间类型:

序号

JavaType

JdbcType

TypeHandler

入口

说明

1

Date.class

JdbcType.DATE

DateOnlyTypeHandler

入口3

 

2

Date.class

JdbcType.TIME

TimeOnlyTypeHandler

 

3

Object.class

JdbcType.OTHER

UNKNOWN_TYPE_HANDLER

 

4

byte[].class

JdbcType.BLOB

BlobTypeHandler

 

5

byte[].class

JdbcType.LONGVARBINARY

BlobTypeHandler

 

6

Byte[].class

JdbcType.BLOB

BlobByteObjectArrayTypeHandler

 

7

Byte[].class

JdbcType.LONGVARBINARY

BlobByteObjectArrayTypeHandler

 

8

String.class

JdbcType.CHAR

StringTypeHandler

 

9

String.class

JdbcType.CLOB

ClobTypeHandler

 

10

String.class

JdbcType.VARCHAR

StringTypeHandler

 

11

String.class

JdbcType.LONGVARCHAR

ClobTypeHandler

 

12

String.class

JdbcType.NVARCHAR

NStringTypeHandler

 

13

String.class

JdbcType.NCHAR

NStringTypeHandler

 

14

String.class

JdbcType.NCLOB

NClobTypeHandler

 

3.2 注册入口计

  通过观察源码我们啊堪发现立即三栽注册方式,我于这里拿及时三种植方式的register方法看做三单输入,分别于名叫也:入口1、入口2、入口3。

  其中:

    入口1:对应之前介绍的首先种植集合(枚举集合),其进口计吧:

1   //入口1
2   public void register(JdbcType jdbcType, TypeHandler<?> handler) {
3     JDBC_TYPE_HANDLER_MAP.put(jdbcType, handler);
4   }

    该入口计用于将项目处理器注册到对应之数据库类型。

    入口2:对应之前介绍的第二栽嵌套集合(其中内层集合的键为null),其输入计吗:

1   //入口2
2   public <T> void register(Class<T> javaType, TypeHandler<? extends T> typeHandler) {
3     register((Type) javaType, typeHandler);
4   }

    该入口计用于将项目处理器注册及对应之Java类型。

    入口3:对应之前介绍的老二种嵌套集合,其输入计吧:

1   //入口3
2   public <T> void register(Class<T> type, JdbcType jdbcType, TypeHandler<? extends T> handler) {
3     register((Type) type, jdbcType, handler);
4   }

    该入口计用于将品种处理器以及Java类型和数据库类型联系起来。

  上述的老三单输入计均是对内而一旦的入口计,也就是说是用于注册器内部基础项目处理器(MyBatis内置的门类处理器)注册下的。而MyBatis还提供了自定义类型处理器的效果,也就是说在此类中尚提供了对外的自定义类型处理器注册入口。

  这么清楚:对内就是欠方式给类似里调用进行注册,对外就是拖欠办法让接近外部的其余类似进行调用而展开注册,这里的别样类似其实就算是XMLConfigBuilder类,它于构建Configuration对象时便会见调用对外的挂号方式,来以用户从定义之路处理器注册及注册器中。

    对外入口1:只指定包名的气象下,这种情形一般要般配注解@MappedTypes使用,使用该注解进行JavaType的装置(即注解的value值)

 1   //对外入口1:扫描器
 2   public void register(String packageName) {
 3     ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
 4     resolverUtil.find(new ResolverUtil.IsA(TypeHandler.class), packageName);
 5     Set<Class<? extends Class<?>>> handlerSet = resolverUtil.getClasses();
 6     for (Class<?> type : handlerSet) {
 7       //Ignore inner classes and interfaces (including package-info.java) and abstract classes
 8       if (!type.isAnonymousClass() && !type.isInterface() && !Modifier.isAbstract(type.getModifiers())) {
 9         register(type);
10       }
11     }
12   }

  这个进口是一个扫描器,它见面采用ResolverUtil工具类在吃定包名下扫描所有类,然后进行巡回注册,注册之前会进展排操作,将其中类、接口、抽象类排除在外。这个扫描器针对的便是我们由定义之类型处理器进行注册,这个进口方法会在构建Configuration配置类时由XMLConfigBuilder进行调用,用于将用户从定义之花色处理器注册到注册器中。

  上面的入口是以指定包名的情景下进行保管扫描来博取包下所发出相近来进展项目处理器注册,一般会配合注解一起以,但是要是非匹配注解也会成功。如果匹配注解指定JavaType,那么它们用和对外入口2的情状一样(指定JavaType与TypeHandler),如果没有配合注解,那么就惟有TypeHandler,这时候会调用另外一个注册方式,在此艺术被会重复验证是否是注解,不设有的话,那么证明得到的类是否是TypeReference接口的兑现类似,如果是实际上现类,说明这看似是一个型处理器,那么再调用另外一个登记方式,以该档处理器的原生类型也参数进行调用,在斯方法吃得查询该项目处理器是否有注解@MappedJdbcTypes来指定JdbcType,如果起则是JdbcType值为数据库类型,如果没有或是Null类型,则直用JdbcType置null再调用核心注册方式,将该项目处理器注册到TYPE_HANDLER_MAP集合中,最后还有用该注册器注册到ALL_TYPE_HANDLERS_MAP中用于统一管理。

    对外入口2:指定Java类型与品类处理器的景象

1   //对外入口2
2   public void register(Class<?> javaTypeClass, Class<?> typeHandlerClass) {
3     register(javaTypeClass, getInstance(javaTypeClass, typeHandlerClass));
4   }

  对于第二种对外入口其实以第一栽的情状遇已经具有描述,这个方法会调用另外一个挂号方式,来用@MappedJdbcTypes获取jdbcType类型,其余步骤和齐。

    对外入口3:指定JavaType、JdbcType、TypeHandler三者的状况

1   //对外入口3
2   public void register(Class<?> javaTypeClass, JdbcType jdbcType, Class<?> typeHandlerClass) {
3     register(javaTypeClass, jdbcType, getInstance(javaTypeClass, typeHandlerClass));
4   }

  这种情形好一直调用核心注册进行挂号即可。

    对外入口4:只指定TypeHandler的场面

 1   //对外入口4
 2   public void register(Class<?> typeHandlerClass) {
 3     boolean mappedTypeFound = false;
 4     MappedTypes mappedTypes = typeHandlerClass.getAnnotation(MappedTypes.class);
 5     if (mappedTypes != null) {
 6       for (Class<?> javaTypeClass : mappedTypes.value()) {
 7         register(javaTypeClass, typeHandlerClass);
 8         mappedTypeFound = true;
 9       }
10     }
11     if (!mappedTypeFound) {
12       register(getInstance(null, typeHandlerClass));
13     }
14   }

  这种气象下,需要事先证是否有@MappedType指定JavaType,再作证是否来@MappedJdbcType指定JdbcType,分各种场面开展考虑,这当第一单输入计吃已经描述。

3.3 核心注册方式

  虽然有不少对内对外的注册入口计,但是几乎都见面因于主导注册方式,只有对内入口1不会见凭借于中心注册方式,因为第一种对内入口计的实施职能是朝枚举集合JDBC_TYPE_HANDLER_MAP中注册数据库类型处理器。这跟其余的挂号情况不同,一般我们的注册是依赖往TYPE_HANDLER_MAP嵌套集合和ALL_TYPE_HANDLERS_MAP集合中注册类型处理器。

 1   private void register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler) {
 2     if (javaType != null) {
 3       Map<JdbcType, TypeHandler<?>> map = TYPE_HANDLER_MAP.get(javaType);
 4       if (map == null) {
 5         map = new HashMap<JdbcType, TypeHandler<?>>();
 6         TYPE_HANDLER_MAP.put(javaType, map);
 7       }
 8       map.put(jdbcType, handler);
 9     }
10     ALL_TYPE_HANDLERS_MAP.put(handler.getClass(), handler);
11   }

  然我来总述一下登记之进程,对点的状况作何总结:

  注册就使三者兼备,哪三哟:javaType、JdbcType、TypeHandler三者兼备,针对于定义类型处理器而言,我们可由此持续BaseTypeHandler抽象类或者实现TypeHandler接口的措施来进展项目处理器的自定义实现。但是为了要其能当MyBatis中发挥作用,我们只要将那个登记到项目处理器注册器中。通过简单的配备即可实现,配置方式有些许种植:

1     <typeHandlers>
2         <package name="com.xx.xx"/>
3         <typeHandler handler="com.xx.xx.XxxTypeHandler" javaType="xxx" jdbcType="JdbcType.xxx" />
4     </typeHandlers>

  若是用第二栽方式安排即可直接进行登记,但是有时我们会看去javaType设置,而使@MappedTypes注解来指定多个JavaType,或者省去JdbcType配置,采用@MappedJdbcTypes注解来指定多只jdbcType(毕竟配置文件只能指定一个,当需要设置多个时,就不得不用注解的章程贯彻),这时便用查询目标处理器类的笺注来赢得类,如果既没在部署文件中布局,也从来不经注解配置,那么就算只好置为null(这种状态到底,少见,一般我们而于定义类型处理器,必定是生某种类型处理器处理的莫如意,我们一定会指定相应之Java类型与数据库类型,如果听的无的的说话我们同时何苦多是一举为?)

  极端情况就算是运包名配置或者单指定处理器类型进行登记,这时用慢慢查看类型处理器类的注释配置来获取该计算机处理的Java类型与数据库类型,最后当两者都获到之情形下,三者兼备,调用核心注册方式,将这类型处理器注册到TYPE_HANDLER_MAP嵌套集合和ALL_TYPE_HANDLERS_MAP集合中。

网站地图xml地图