读书人

ibatis源码分析(待续.) in 2009

发布时间: 2012-11-04 10:42:42 作者: rapoo

ibatis源码分析(待续...) in 2009

?

ibatis版本号:

2.3.0

Build Date: 2006/11/30 17:16
Build Number: 677

ibatis的技术是从xml里面字符串转换成JAVA对象,对象填充JDBC的statement查询,然后从resultset取对象返回,另外利用ThreadLocal实现线程安全,JDBC保证了事务控制,cache(三方库)实现缓存的dao框架。

?

各大包结构和作用:
ibatis源码分析(待续.) in 2009
?

?

1,accessplan—

2,builder.xml

3,cache

4,datasource

5,exchange—ResultMap(sql结果类型结构)和ParameterMap(sql条件类型结果)与值的相互转换

6,execution

7,impl

8,mapping

9,scop

10,transaction

11,type—jdbc的Statement和ResultSet 与 java.lang.Object对象的相互转换。

Accessplan

uml:

?


ibatis源码分析(待续.) in 2009
?

Accessplan对外只提供个Factory,这种“封闭”设计可以借鉴:

对外接口调用如下:

    parameterPlan = AccessPlanFactory.getAccessPlan(parameterMap.getParameterClass(), parameterPropNames);

其中parameterMap.getParameterClass(),是映射的CLASS,就是XML里parameterXXX里的类,后面那个是类的成员变量,ParameterMapping是映射元素类,如下:

? // 从某个映射对象中取出所有元素

? ParameterMapping[] parameterMappings = parameterMap.getParameterMappings();


??????? String[] parameterPropNames = new String[parameterMappings.length];
??????? for (int i = 0; i < parameterPropNames.length; i++) {

// 从元素中取出被映射对象的成员名
????????? parameterPropNames[i] = parameterMappings[i].getPropertyName();
??????? }

?

?


?UML:

?

?
ibatis源码分析(待续.) in 2009

?

ibatis源码分析(待续.) in 2009
?

ResultGetter和ParameterSetter的设计看来是为了TypeHandlerCallback扩展的复杂数据类型所用。为什么需要在这中间加一层呢? 可能是因为数据的复杂性吧,把特例和一般分离出来,代码看上去似乎优雅些。继续深入。
?

?元数据接口

?

TypeHandler接口的抽象意义——Interface for getting data into, and out of a mapped statement,主要的作用是把Object那些对象set到jdbc的statement,以及从resultset结果集中获取那些Object对象。

/*** Interface for getting data into, and out of a mapped statement*/public interface TypeHandler {  // para向第i个位置填充ps.   public void setParameter(PreparedStatement ps, int i, Object parameter, String jdbcType)      throws SQLException;  // 根据rs结果集某字段名取值  public Object getResult(ResultSet rs, String columnName)      throws SQLException;  public Object getResult(ResultSet rs, int columnIndex)      throws SQLException;  /**   * Converts the String to the type that this handler deals with   */  public Object valueOf(String s);  public boolean equals(Object object, String string);}

??

TypeHandlerCallback接口抽象意义为:

A simple interface for implementing custom type handlers.
Using this interface, you can implement a type handler that
will perform customized processing before parameters are set
on a PreparedStatement and after values are retrieved from
a ResultSet.

?

public interface TypeHandlerCallback {  public void setParameter(ParameterSetter setter, Object parameter) // 同上      throws SQLException;  public Object getResult(ResultGetter getter) // 同上      throws SQLException;  public Object valueOf(String s);}

?

?StringTypeHandler——String类型帮助类

public class StringTypeHandler extends BaseTypeHandler implements TypeHandler {  public void setParameter(PreparedStatement ps, int i, Object parameter, String jdbcType)      throws SQLException {    ps.setString(i, ((String) parameter));  }  public Object getResult(ResultSet rs, String columnName)      throws SQLException {    Object s = rs.getString(columnName); // 很熟悉的jdbc编程吧    if (rs.wasNull()) {      return null;    } else {      return s;    }  }  public Object getResult(ResultSet rs, int columnIndex)      throws SQLException {    Object s = rs.getString(columnIndex);    if (rs.wasNull()) {      return null;    } else {      return s;    }  }}

?最后“元数据”这块剩下最后一个Factory管理类:TypeHandlerFactory

?

/** * Not much of a suprise, this is a factory class for TypeHandler objects. */public class TypeHandlerFactory {  private final Map typeHandlerMap = new HashMap(); // 用final Map来存储类型转换的帮助类  private final TypeHandler unknownTypeHandler = new UnknownTypeHandler(this);  private final HashMap typeAliases = new HashMap();// 保存type助记符,为什么呢?  /**   * Default constructor   */  public TypeHandlerFactory() {    TypeHandler handler;    handler = new BooleanTypeHandler();    register(Boolean.class, handler);// 实际上把handler放入布尔值的map,然后再放入typeMap里。  register(boolean.class, handler);    handler = new ByteTypeHandler();    register(Byte.class, handler);    register(byte.class, handler);    register(String.class, new StringTypeHandler());    register(String.class, "CLOB", new CustomTypeHandler(new ClobTypeHandlerCallback()));    register(String.class, "LONGVARCHAR", new CustomTypeHandler(new ClobTypeHandlerCallback()));    register(byte[].class, new ByteArrayTypeHandler());    register(byte[].class, "BLOB", new CustomTypeHandler(new BlobTypeHandlerCallback()));    register(byte[].class, "LONGVARBINARY", new CustomTypeHandler(new BlobTypeHandlerCallback()));   ....    putTypeAlias("string", String.class.getName());    putTypeAlias("byte", Byte.class.getName());    putTypeAlias("long", Long.class.getName());   ....  }  /* Public Methods */  public TypeHandler getTypeHandler(Class type, String jdbcType) {    Map jdbcHandlerMap = (Map) typeHandlerMap.get(type);    TypeHandler handler = null;    if (jdbcHandlerMap != null) {      handler = (TypeHandler) jdbcHandlerMap.get(jdbcType);      if (handler == null) {        handler = (TypeHandler) jdbcHandlerMap.get(null);      }    }    return handler;  }  /**   * When in doubt, get the "unknown" type handler   *    * @return - if I told you, it would not be unknown, would it?   */  public TypeHandler getUnkownTypeHandler() {    return unknownTypeHandler;  }  /**   * Tells you if a particular class has a TypeHandler   *    * @param type - the class   *    * @return - true if there is a TypeHandler   */  public boolean hasTypeHandler(Class type) {    return getTypeHandler(type) != null;  }  /**   * Register (add) a type handler for a class and JDBC type   *    * @param type - the class   * @param jdbcType - the JDBC type   * @param handler - the handler instance   */  public void register(Class type, String jdbcType, TypeHandler handler) {    Map map = (Map) typeHandlerMap.get(type);    if (map == null) {      map = new HashMap();      typeHandlerMap.put(type, map);    }    map.put(jdbcType, handler);  }  /**   * Lookup an aliased class and return it's REAL name   *    * @param string - the alias   *    * @return - the REAL name   */  public String resolveAlias(String string) {    String key = null;    if(string != null)      key = string.toLowerCase();    String value = null;    if (typeAliases.containsKey(key)) {      value = (String) typeAliases.get(key);    } else {      value = string;    }    return value;  }  /**   * Adds a type alias that is case insensitive.  All of the following String, string, StRiNg will equate to the same alias.   * @param alias - the alias   * @param value - the real class name   */  public void putTypeAlias(String alias, String value) {    String key = null;    if(alias != null)      key = alias.toLowerCase();    if (typeAliases.containsKey(key) && !typeAliases.get(key).equals(value)) {      throw new SqlMapException("Error in XmlSqlMapClientBuilder.  Alias name conflict occurred.  The alias '" + key + "' is already mapped to the value '" + typeAliases.get(alias) + "'.");    }    typeAliases.put(key, value);  }}

?

?

?Mapping包

?

?? --parameter包意义——主要负责数据类型转换,把xml写的字符串映射成正确的类型,以上type包是解决了object到type的转换。

?

??? UML:

ibatis源码分析(待续.) in 2009?

?

ParameterMap接口

?

public interface ParameterMap {  public String getId();  public void setParameters(RequestScope request, PreparedStatement ps, Object[] parameters)      throws SQLException;  public Object[] getParameterObjectValues(RequestScope request, Object parameterObject);  public CacheKey getCacheKey(RequestScope request, Object parameterObject);  public void refreshParameterObjectValues(RequestScope request, Object parameterObject, Object[] values);  public ParameterMapping[] getParameterMappings();  public Class getParameterClass();}

?

ParameterMapping接口

?

public interface ParameterMapping {  public String getPropertyName();  public boolean isOutputAllowed();}

?

BasicParameterMapping实现类:

?

public class BasicParameterMapping implements ParameterMapping {  private static final String MODE_INOUT = "INOUT";  private static final String MODE_OUT = "OUT";  private static final String MODE_IN = "IN";  private String propertyName; // 从XML文件里读取需要转换的类型名  private TypeHandler typeHandler; // 对象转换相应类型的工具map  private String typeName; // this is used for REF types or user-defined types  private int jdbcType;  private String jdbcTypeName;  private String nullValue;  private String mode;  private boolean inputAllowed;  private boolean outputAllowed;  private Class javaType; // 需要转换的类型class  private String resultMapName; // 结果map名称  private Integer numericScale;  private String errorString;  public BasicParameterMapping() {    mode = "IN";    inputAllowed = true;    outputAllowed = false;  }  public void setJavaTypeName(String javaTypeName) {    try {      if (javaTypeName == null) {        this.javaType = null;      } else {// 通过getClassLoader().loadClass(className);来获得实例        this.javaType = Resources.classForName(javaTypeName);      }    } catch (ClassNotFoundException e) {      throw new SqlMapException("Error setting javaType property of ParameterMap.  Cause: " + e, e);    }  }}

?

?

?

BasicParameterMap实现类

?

public class BasicParameterMap implements ParameterMap {  private String id;  private Class parameterClass;  private ParameterMapping[] parameterMappings;  private DataExchange dataExchange;  private String resource;  private Map parameterMappingIndex = new HashMap();  private SqlMapExecutorDelegate delegate;  public void setParameterMappingList(List parameterMappingList) {    this.parameterMappings = (BasicParameterMapping[]) parameterMappingList.toArray(new BasicParameterMapping[parameterMappingList.size()]);    for (int i = 0; i < parameterMappings.length; i++) {      parameterMappingIndex.put(parameterMappings[i].getPropertyName(), new Integer(i));    }    Map props = new HashMap();    props.put("map", this);    dataExchange = delegate.getDataExchangeFactory().getDataExchangeForClass(parameterClass);    dataExchange.initialize(props);  }  /**   * @param ps   * @param parameters   * @throws java.sql.SQLException   */  public void setParameters(RequestScope request, PreparedStatement ps, Object[] parameters)      throws SQLException {    ErrorContext errorContext = request.getErrorContext();    errorContext.setActivity("applying a parameter map");    errorContext.setObjectId(this.getId());    errorContext.setResource(this.getResource());    errorContext.setMoreInfo("Check the parameter map.");    if (parameterMappings != null) {      for (int i = 0; i < parameterMappings.length; i++) {        BasicParameterMapping mapping = (BasicParameterMapping) parameterMappings[i];        errorContext.setMoreInfo(mapping.getErrorString());        if (mapping.isInputAllowed()) {          setParameter(ps, mapping, parameters, i);        }      }    }  }  public Object[] getParameterObjectValues(RequestScope request, Object parameterObject) {    return dataExchange.getData(request, this, parameterObject);  }  public CacheKey getCacheKey(RequestScope request, Object parameterObject) {    return dataExchange.getCacheKey(request, this, parameterObject);  }  public void refreshParameterObjectValues(RequestScope request, Object parameterObject, Object[] values) {    dataExchange.setData(request, this, parameterObject, values);  }  protected void setParameter(PreparedStatement ps, BasicParameterMapping mapping, Object[] parameters, int i) throws SQLException {    Object value = parameters[i];    // Apply Null Value    String nullValueString = mapping.getNullValue();    if (nullValueString != null) {      TypeHandler handler = mapping.getTypeHandler();      if (handler.equals(value, nullValueString)) {        value = null;      }    }    // Set Parameter    TypeHandler typeHandler = mapping.getTypeHandler();    if (value != null) {      typeHandler.setParameter(ps, i + 1, value, mapping.getJdbcTypeName());    } else if (typeHandler instanceof CustomTypeHandler) {      typeHandler.setParameter(ps, i + 1, value, mapping.getJdbcTypeName());    } else {      int jdbcType = mapping.getJdbcType();      if (jdbcType != JdbcTypeRegistry.UNKNOWN_TYPE) {        ps.setNull(i + 1, jdbcType);      } else {        ps.setNull(i + 1, Types.OTHER);      }    }  }}

?

读书人网 >软件架构设计

热点推荐