- 浏览: 14335 次
- 性别:
- 来自: 成都
最新评论
MyBatis执行两种方式:
1.
2.
方式1:
1.DefaultSqlSessionFactory
Configuration#newExecutor 生成相应的Executor
SqlSession构造完毕后执行selectOne方法:
RowBounds //TODO
继续调用重载的selectList
DefaultSqlSession //TODO
执行Executor的query方法:
MapperStatement#getBoundSql
DynamicContext:
Configuration#newMetaObject
MetaObject:
BeanWrapper://TODO
MetaClass:参考启动流程2
BaseWrapper://TODO
分析一下调用链:
1.Configuration传入:
object, objectFactory, objectWrapperFactory, reflectorFactory
object为参数对象ObjectFactory即对象工厂,通过反射创建对象,
objectWrapperFactory是DefaultObjectWrapperFactory,其为空实现,实现了ObjectWrapperFactory,先不说明有什么作用,
reflectorFactory则非常重要,包含了Reflector的缓存,Reflector则是封装了一个类型的getter setter和相应实现了InvokcationHandler接口的Invoker,用来设置相应的属性值。
2。MetaObject 构造相应的Wrapper实现,构造几种BeanWrapper时都传入了this即MetaObject,MetaObject有两个作用:供抽象父类BaseWrapper调用MetaObject方法和获取MetaObject的reflectorFactory,通过reflectorFactory可以构造MetaClass,MetaClass则是Relector的封装。查看BeanWrapper的get方法调用了getBeanProperty而这个方法继续调用了metaClass.getGetInvoker即reflector的getGetInvoker。而MetaObject的getValue方法则调用了objectWrapper的get方法。
总结一下:为什么要将一个简单的Invoker对象封装如此多层呢?有什么具体的作用呢?
只要通过MetaOject的getValue方法就可以将任何对象封装成像一个Map医院使用。
DynamicContext的作用:DynamicContext 包含实例变量ContextMap和sqlBuilder,ContextMap中有传入如parameterObject和DatabaseId。还有什么用?//TODO
继续执行DynamicSqlSource#getBoundSql
这里的rootSqlNode是解析流程(3)中的MixedSqlNode的实例,MixedSqlNode中contents存储了所有解析后的动态和静态的SqlNode的实现。所有MixedSqlNode的apply方法仅仅是执行contents中的SqlNode的apply方法,apply方法只有一个入参DynamicContext
如果sqlNode是StaticTextSqlNode,调用 context.appendSql(text);将静态sql文本加在context的sqlBuilder尾部
如果是IfSqlNode调用Ogln解析器解析使用binds赋值的test表达式成功则添加否则不添加。
继续执行
执行到这里可以发现SqlNode的主要作用就动态的拼接sql语句,产出sql语句,而DynamicContext的作用就是产出sql(待#{}表达式)和将入参封装为Map(contextMap)对象。
SqlSourceBuilder和内部类都继承了BaseBuilder表明自己是个解析器并且获得了 typeAliasRegistry、typeHandlerRegistry两个属性 和一些基本的方法。
protected final TypeHandlerRegistry typeHandlerRegistry;
ParameterMapping://TODO
继续执行SqlSourceBuilder#parse,生成StaticSqlSource,
BoundSql:
观察BoundSql和StaticSqlSource,发现BoundSql只比StaticSqlSource多了metaParameters的参数。
执行到这里不妨总结一下Sql解析的流程和使用到的几个核心类、接口:
在mapper解析阶段XMLScriptBuilder#parseDynamicTags生成MixedSqlNode和
parseScriptNode生成DynamicSqlSource组装生成MappedStatement,执行时传入参数并执行DynamicSqlSource中rootSqlNode最终生成静态的StaticSqlSource,静态的StaticSqlSource是已经解析成jdbc驱动可以执行的语句,进一步加上入参对象封装而成的MetaObject成了BoundSql。
SqlNode接口:表示每个sql片段,有两种实现类,动态:的有if where 等和静态的sql片段,表示不含表达式的sql语句。此接口只包含一个方法,此方法入参为DynamicContext,每次调用判断将sql追加到上下文的末尾,形成整个一个语句。各种SqlNode在XMLScriptBuilder#parseDynamicTags被创建加入一个MixedSqlNode中,MapperStatement的rootSqlNode执行apply后销亡。
ParameterMapping:包含当前#{}中包含的参数对象类型的属性名称、类型等,执行阶段被ParameterMappingTokenHandler#buildParameterMapping或者MapperBuilderAssistant#buildParameterMapping生成,并加入SqlSource
SqlSource:在动态的SqlSource包含SqlNode的实例,静态SqlSource包含解析后的sql和参数映射ParameterMapping,DynamicSqlSource在解析阶段使用,StaticSqlSource在执行阶段使用。
BoundSql:包含静态sql语句,ParameterMapping参数映射,parameterObject原生传入参数,additionalParameters额外的参数( DynamicContext中所有的值)以及metaParameters,额外参数对应的获取方法,BoundSql包含了一个sql得以执行的所有必需条件。
继续执行MapperStatement#getBoundSql
到此MapperStatement的getBoundSql就执行完成了
1.
SqlSession openSession = sqlSessionFactory.openSession(); Dept d = new Dept(); d.setId(1506720); Object dept = openSession.selectOne("dao.DeptDAO1.select",d); System.out.println(dept);
2.
DeptMapper mapper = openSession.getMapper(DeptMapper.class); Dept dept2= mapper.select(d); System.out.println(dept2);
方式1:
1.DefaultSqlSessionFactory
@Override public SqlSession openSession() { return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false); } public ExecutorType getDefaultExecutorType() { return defaultExecutorType; } protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE; public enum ExecutorType { SIMPLE, REUSE, BATCH } private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; try { //XMLConfigBuilder#environmentsElement加载 final Environment environment = configuration.getEnvironment(); final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); //新建一个事务 tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); final Executor executor = configuration.newExecutor(tx, execType); return new DefaultSqlSession(configuration, executor, autoCommit); } catch (Exception e) { closeTransaction(tx); // may have fetched a connection so lets call close() throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }
Configuration#newExecutor 生成相应的Executor
public Executor newExecutor(Transaction transaction, ExecutorType executorType) { executorType = executorType == null ? defaultExecutorType : executorType; executorType = executorType == null ? ExecutorType.SIMPLE : executorType; Executor executor; if (ExecutorType.BATCH == executorType) { executor = new BatchExecutor(this, transaction); } else if (ExecutorType.REUSE == executorType) { executor = new ReuseExecutor(this, transaction); } else { executor = new SimpleExecutor(this, transaction); } //缓存 if (cacheEnabled) { //后面统一分析Executor集合和其子类,这里将SimpleExecutor包装为一个 //CachingExecutor executor = new CachingExecutor(executor); } //调用拦截器链中注册的拦截器(如果拦截类型是Executor),每个拦截器会对当前 //Executor进行动态代理,如果有n个拦截器拦截Executor,会生成对Executor的n层代理, //后面再进行详细分析 executor = (Executor) interceptorChain.pluginAll(executor); return executor; }
SqlSession构造完毕后执行selectOne方法:
@Override public <T> T selectOne(String statement, Object parameter) { // Popular vote was to return null on 0 results and throw exception on too many. List<T> list = this.<T>selectList(statement, parameter); if (list.size() == 1) { return list.get(0); } else if (list.size() > 1) { throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size()); } else { return null; } } @Override public <E> List<E> selectList(String statement, Object parameter) { return this.selectList(statement, parameter, RowBounds.DEFAULT); }
RowBounds //TODO
继续调用重载的selectList
@Override public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { try { MappedStatement ms = configuration.getMappedStatement(statement); return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER); } catch (Exception e) { throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } } //包装参数为StrictMap private Object wrapCollection(final Object object) { if (object instanceof Collection) { StrictMap<Object> map = new StrictMap<Object>(); map.put("collection", object); if (object instanceof List) { map.put("list", object); } return map; } else if (object != null && object.getClass().isArray()) { StrictMap<Object> map = new StrictMap<Object>(); map.put("array", object); return map; } return object; }
DefaultSqlSession //TODO
执行Executor的query方法:
@Override public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { //获取带?号的sql和参数映射 BoundSql boundSql = ms.getBoundSql(parameterObject); CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql); return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }
MapperStatement#getBoundSql
public BoundSql getBoundSql(Object parameterObject) { //调用SqlSource的getBoundSql,这里的sqlSource是DymicSqlSource的一个实例 //见前一篇文章XMLScriptBuilder#parseScriptNode // sqlSource = new DynamicSqlSource(configuration, rootSqlNode); BoundSql boundSql = sqlSource.getBoundSql(parameterObject); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); //如果参数映射为空才考虑使用ParameterMap //ParameterMap在mapper解析 insert update select 等标签时生成 if (parameterMappings == null || parameterMappings.isEmpty()) { boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject); } //检查ParameterMap是否有嵌套的ResultMap // check for nested result maps in parameter mappings (issue #30) for (ParameterMapping pm : boundSql.getParameterMappings()) { String rmId = pm.getResultMapId(); if (rmId != null) { ResultMap rm = configuration.getResultMap(rmId); if (rm != null) { hasNestedResultMaps |= rm.hasNestedResultMaps(); } } } return boundSql; }
//SqlSource一共有四个子类:ProviderSqlSource,DynamicSqlSource、RawSqlSource、StaticSqlSource public class DynamicSqlSource implements SqlSource { private final Configuration configuration; private final SqlNode rootSqlNode; public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode) { this.configuration = configuration; this.rootSqlNode = rootSqlNode; } @Override public BoundSql getBoundSql(Object parameterObject) { DynamicContext context = new DynamicContext(configuration, parameterObject); rootSqlNode.apply(context); SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration); Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass(); SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings()); BoundSql boundSql = sqlSource.getBoundSql(parameterObject); for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) { boundSql.setAdditionalParameter(entry.getKey(), entry.getValue()); } return boundSql; } }
DynamicContext:
public class DynamicContext { public static final String PARAMETER_OBJECT_KEY = "_parameter"; public static final String DATABASE_ID_KEY = "_databaseId"; static { //初始化OgnlRuntime使用ContextAccessor作为访问器 OgnlRuntime.setPropertyAccessor(ContextMap.class, new ContextAccessor()); } private final ContextMap bindings; private final StringBuilder sqlBuilder = new StringBuilder(); private int uniqueNumber = 0; //如果当前参数是实体对象或者List的子类等其他对象,反正不是Map public DynamicContext(Configuration configuration, Object parameterObject) { //当前参数不是map的实例 if (parameterObject != null && !(parameterObject instanceof Map)) { MetaObject metaObject = configuration.newMetaObject(parameterObject); bindings = new ContextMap(metaObject); } else { //为空或者是Map bindings = new ContextMap(null); } //将对象参数放入 key为_parameter的map中 bindings.put(PARAMETER_OBJECT_KEY, parameterObject); bindings.put(DATABASE_ID_KEY, configuration.getDatabaseId()); } public Map<String, Object> getBindings() { return bindings; } public void bind(String name, Object value) { bindings.put(name, value); } public void appendSql(String sql) { sqlBuilder.append(sql); sqlBuilder.append(" "); } public String getSql() { return sqlBuilder.toString().trim(); } public int getUniqueNumber() { return uniqueNumber++; } static class ContextMap extends HashMap<String, Object> { private static final long serialVersionUID = 2977601501966151582L; private MetaObject parameterMetaObject; public ContextMap(MetaObject parameterMetaObject) { this.parameterMetaObject = parameterMetaObject; } @Override public Object get(Object key) { String strKey = (String) key; if (super.containsKey(strKey)) { return super.get(strKey); } if (parameterMetaObject != null) { // issue #61 do not modify the context when reading return parameterMetaObject.getValue(strKey); } return null; } } static class ContextAccessor implements PropertyAccessor { @Override public Object getProperty(Map context, Object target, Object name) throws OgnlException { Map map = (Map) target; //直接获取contextMap中的keyvalue或者获取MetaObject中的getValue Object result = map.get(name); if (map.containsKey(name) || result != null) { return result; } //如参数对象本身是个map,直接获取 Object parameterObject = map.get(PARAMETER_OBJECT_KEY); if (parameterObject instanceof Map) { return ((Map)parameterObject).get(name); } return null; } @Override public void setProperty(Map context, Object target, Object name, Object value) throws OgnlException { Map<Object, Object> map = (Map<Object, Object>) target; map.put(name, value); } @Override public String getSourceAccessor(OgnlContext arg0, Object arg1, Object arg2) { return null; } @Override public String getSourceSetter(OgnlContext arg0, Object arg1, Object arg2) { return null; } } }
Configuration#newMetaObject
public MetaObject newMetaObject(Object object) { return MetaObject.forObject(object, objectFactory, objectWrapperFactory, reflectorFactory); }
MetaObject:
public class MetaObject { private final Object originalObject; private final ObjectWrapper objectWrapper; private final ObjectFactory objectFactory; private final ObjectWrapperFactory objectWrapperFactory; private final ReflectorFactory reflectorFactory; private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) { this.originalObject = object; this.objectFactory = objectFactory; this.objectWrapperFactory = objectWrapperFactory; this.reflectorFactory = reflectorFactory; if (object instanceof ObjectWrapper) { this.objectWrapper = (ObjectWrapper) object; } else if (objectWrapperFactory.hasWrapperFor(object)) { this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object); } else if (object instanceof Map) { this.objectWrapper = new MapWrapper(this, (Map) object); } else if (object instanceof Collection) { this.objectWrapper = new CollectionWrapper(this, (Collection) object); } else { // 首次进入执行BeanWapper this.objectWrapper = new BeanWrapper(this, object); } } public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) { if (object == null) { return SystemMetaObject.NULL_META_OBJECT; } else { return new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory); } } public ObjectFactory getObjectFactory() { return objectFactory; } public ObjectWrapperFactory getObjectWrapperFactory() { return objectWrapperFactory; } public ReflectorFactory getReflectorFactory() { return reflectorFactory; } public Object getOriginalObject() { return originalObject; } public String findProperty(String propName, boolean useCamelCaseMapping) { return objectWrapper.findProperty(propName, useCamelCaseMapping); } public String[] getGetterNames() { return objectWrapper.getGetterNames(); } public String[] getSetterNames() { return objectWrapper.getSetterNames(); } public Class<?> getSetterType(String name) { return objectWrapper.getSetterType(name); } public Class<?> getGetterType(String name) { return objectWrapper.getGetterType(name); } public boolean hasSetter(String name) { return objectWrapper.hasSetter(name); } public boolean hasGetter(String name) { return objectWrapper.hasGetter(name); } public Object getValue(String name) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { MetaObject metaValue = metaObjectForProperty(prop.getIndexedName()); if (metaValue == SystemMetaObject.NULL_META_OBJECT) { return null; } else { return metaValue.getValue(prop.getChildren()); } } else { return objectWrapper.get(prop); } } public void setValue(String name, Object value) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { MetaObject metaValue = metaObjectForProperty(prop.getIndexedName()); if (metaValue == SystemMetaObject.NULL_META_OBJECT) { if (value == null && prop.getChildren() != null) { // don't instantiate child path if value is null return; } else { metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory); } } metaValue.setValue(prop.getChildren(), value); } else { objectWrapper.set(prop, value); } } public MetaObject metaObjectForProperty(String name) { Object value = getValue(name); return MetaObject.forObject(value, objectFactory, objectWrapperFactory, reflectorFactory); } public ObjectWrapper getObjectWrapper() { return objectWrapper; } public boolean isCollection() { return objectWrapper.isCollection(); } public void add(Object element) { objectWrapper.add(element); } public <E> void addAll(List<E> list) { objectWrapper.addAll(list); } }
BeanWrapper://TODO
ublic class BeanWrapper extends BaseWrapper { private final Object object; private final MetaClass metaClass; public BeanWrapper(MetaObject metaObject, Object object) { super(metaObject); this.object = object; this.metaClass = MetaClass.forClass(object.getClass(), metaObject.getReflectorFactory()); } @Override public Object get(PropertyTokenizer prop) { if (prop.getIndex() != null) { Object collection = resolveCollection(prop, object); return getCollectionValue(prop, collection); } else { return getBeanProperty(prop, object); } } @Override public void set(PropertyTokenizer prop, Object value) { if (prop.getIndex() != null) { Object collection = resolveCollection(prop, object); setCollectionValue(prop, collection, value); } else { setBeanProperty(prop, object, value); } } @Override public String findProperty(String name, boolean useCamelCaseMapping) { return metaClass.findProperty(name, useCamelCaseMapping); } @Override public String[] getGetterNames() { return metaClass.getGetterNames(); } @Override public String[] getSetterNames() { return metaClass.getSetterNames(); } @Override public Class<?> getSetterType(String name) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName()); if (metaValue == SystemMetaObject.NULL_META_OBJECT) { return metaClass.getSetterType(name); } else { return metaValue.getSetterType(prop.getChildren()); } } else { return metaClass.getSetterType(name); } } @Override public Class<?> getGetterType(String name) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName()); if (metaValue == SystemMetaObject.NULL_META_OBJECT) { return metaClass.getGetterType(name); } else { return metaValue.getGetterType(prop.getChildren()); } } else { return metaClass.getGetterType(name); } } @Override public boolean hasSetter(String name) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { if (metaClass.hasSetter(prop.getIndexedName())) { MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName()); if (metaValue == SystemMetaObject.NULL_META_OBJECT) { return metaClass.hasSetter(name); } else { return metaValue.hasSetter(prop.getChildren()); } } else { return false; } } else { return metaClass.hasSetter(name); } } @Override public boolean hasGetter(String name) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { if (metaClass.hasGetter(prop.getIndexedName())) { MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName()); if (metaValue == SystemMetaObject.NULL_META_OBJECT) { return metaClass.hasGetter(name); } else { return metaValue.hasGetter(prop.getChildren()); } } else { return false; } } else { return metaClass.hasGetter(name); } } @Override public MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) { MetaObject metaValue; Class<?> type = getSetterType(prop.getName()); try { Object newObject = objectFactory.create(type); metaValue = MetaObject.forObject(newObject, metaObject.getObjectFactory(), metaObject.getObjectWrapperFactory(), metaObject.getReflectorFactory()); set(prop, newObject); } catch (Exception e) { throw new ReflectionException("Cannot set value of property '" + name + "' because '" + name + "' is null and cannot be instantiated on instance of " + type.getName() + ". Cause:" + e.toString(), e); } return metaValue; } private Object getBeanProperty(PropertyTokenizer prop, Object object) { try { Invoker method = metaClass.getGetInvoker(prop.getName()); try { return method.invoke(object, NO_ARGUMENTS); } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } } catch (RuntimeException e) { throw e; } catch (Throwable t) { throw new ReflectionException("Could not get property '" + prop.getName() + "' from " + object.getClass() + ". Cause: " + t.toString(), t); } } private void setBeanProperty(PropertyTokenizer prop, Object object, Object value) { try { Invoker method = metaClass.getSetInvoker(prop.getName()); Object[] params = {value}; try { method.invoke(object, params); } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } } catch (Throwable t) { throw new ReflectionException("Could not set property '" + prop.getName() + "' of '" + object.getClass() + "' with value '" + value + "' Cause: " + t.toString(), t); } } @Override public boolean isCollection() { return false; } @Override public void add(Object element) { throw new UnsupportedOperationException(); } @Override public <E> void addAll(List<E> list) { throw new UnsupportedOperationException(); } }
MetaClass:参考启动流程2
BaseWrapper://TODO
public abstract class BaseWrapper implements ObjectWrapper { protected static final Object[] NO_ARGUMENTS = new Object[0]; protected final MetaObject metaObject; protected BaseWrapper(MetaObject metaObject) { this.metaObject = metaObject; } protected Object resolveCollection(PropertyTokenizer prop, Object object) { if ("".equals(prop.getName())) { return object; } else { return metaObject.getValue(prop.getName()); } } protected Object getCollectionValue(PropertyTokenizer prop, Object collection) { if (collection instanceof Map) { return ((Map) collection).get(prop.getIndex()); } else { int i = Integer.parseInt(prop.getIndex()); if (collection instanceof List) { return ((List) collection).get(i); } else if (collection instanceof Object[]) { return ((Object[]) collection)[i]; } else if (collection instanceof char[]) { return ((char[]) collection)[i]; } else if (collection instanceof boolean[]) { return ((boolean[]) collection)[i]; } else if (collection instanceof byte[]) { return ((byte[]) collection)[i]; } else if (collection instanceof double[]) { return ((double[]) collection)[i]; } else if (collection instanceof float[]) { return ((float[]) collection)[i]; } else if (collection instanceof int[]) { return ((int[]) collection)[i]; } else if (collection instanceof long[]) { return ((long[]) collection)[i]; } else if (collection instanceof short[]) { return ((short[]) collection)[i]; } else { throw new ReflectionException("The '" + prop.getName() + "' property of " + collection + " is not a List or Array."); } } } protected void setCollectionValue(PropertyTokenizer prop, Object collection, Object value) { if (collection instanceof Map) { ((Map) collection).put(prop.getIndex(), value); } else { int i = Integer.parseInt(prop.getIndex()); if (collection instanceof List) { ((List) collection).set(i, value); } else if (collection instanceof Object[]) { ((Object[]) collection)[i] = value; } else if (collection instanceof char[]) { ((char[]) collection)[i] = (Character) value; } else if (collection instanceof boolean[]) { ((boolean[]) collection)[i] = (Boolean) value; } else if (collection instanceof byte[]) { ((byte[]) collection)[i] = (Byte) value; } else if (collection instanceof double[]) { ((double[]) collection)[i] = (Double) value; } else if (collection instanceof float[]) { ((float[]) collection)[i] = (Float) value; } else if (collection instanceof int[]) { ((int[]) collection)[i] = (Integer) value; } else if (collection instanceof long[]) { ((long[]) collection)[i] = (Long) value; } else if (collection instanceof short[]) { ((short[]) collection)[i] = (Short) value; } else { throw new ReflectionException("The '" + prop.getName() + "' property of " + collection + " is not a List or Array."); } } } }
分析一下调用链:
1.Configuration传入:
object, objectFactory, objectWrapperFactory, reflectorFactory
object为参数对象ObjectFactory即对象工厂,通过反射创建对象,
objectWrapperFactory是DefaultObjectWrapperFactory,其为空实现,实现了ObjectWrapperFactory,先不说明有什么作用,
reflectorFactory则非常重要,包含了Reflector的缓存,Reflector则是封装了一个类型的getter setter和相应实现了InvokcationHandler接口的Invoker,用来设置相应的属性值。
2。MetaObject 构造相应的Wrapper实现,构造几种BeanWrapper时都传入了this即MetaObject,MetaObject有两个作用:供抽象父类BaseWrapper调用MetaObject方法和获取MetaObject的reflectorFactory,通过reflectorFactory可以构造MetaClass,MetaClass则是Relector的封装。查看BeanWrapper的get方法调用了getBeanProperty而这个方法继续调用了metaClass.getGetInvoker即reflector的getGetInvoker。而MetaObject的getValue方法则调用了objectWrapper的get方法。
public Object getValue(String name) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { MetaObject metaValue = metaObjectForProperty(prop.getIndexedName()); if (metaValue == SystemMetaObject.NULL_META_OBJECT) { return null; } else { return metaValue.getValue(prop.getChildren()); } } else { return objectWrapper.get(prop); } }
总结一下:为什么要将一个简单的Invoker对象封装如此多层呢?有什么具体的作用呢?
只要通过MetaOject的getValue方法就可以将任何对象封装成像一个Map医院使用。
DynamicContext的作用:DynamicContext 包含实例变量ContextMap和sqlBuilder,ContextMap中有传入如parameterObject和DatabaseId。还有什么用?//TODO
继续执行DynamicSqlSource#getBoundSql
这里的rootSqlNode是解析流程(3)中的MixedSqlNode的实例,MixedSqlNode中contents存储了所有解析后的动态和静态的SqlNode的实现。所有MixedSqlNode的apply方法仅仅是执行contents中的SqlNode的apply方法,apply方法只有一个入参DynamicContext
rootSqlNode.apply(context);
如果sqlNode是StaticTextSqlNode,调用 context.appendSql(text);将静态sql文本加在context的sqlBuilder尾部
public class MixedSqlNode implements SqlNode { private final List<SqlNode> contents; public MixedSqlNode(List<SqlNode> contents) { this.contents = contents; } @Override public boolean apply(DynamicContext context) { //最终都会执行StaticTextSqlNode的apply方法,将sql拼接在Dynamic中的sqlBuilder中 for (SqlNode sqlNode : contents) { sqlNode.apply(context); } return true; } }
如果是IfSqlNode调用Ogln解析器解析使用binds赋值的test表达式成功则添加否则不添加。
public class IfSqlNode implements SqlNode { private final ExpressionEvaluator evaluator; private final String test; //IfSqlNode也包含contents,可能是MixedSqlNode,StaticTextSqlNode private final SqlNode contents; public IfSqlNode(SqlNode contents, String test) { this.test = test; this.contents = contents; this.evaluator = new ExpressionEvaluator(); } @Override public boolean apply(DynamicContext context) { //判断test表达式值,这里通过DynamicContext.ContextAccessor的getProperty方法调用ContextMap中的get方法继而调用MetaObject的getValue最终获取到传入对象的属性值。 if (evaluator.evaluateBoolean(test, context.getBindings())) { contents.apply(context); return true; } return false; }
继续执行
SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration); SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
执行到这里可以发现SqlNode的主要作用就动态的拼接sql语句,产出sql语句,而DynamicContext的作用就是产出sql(待#{}表达式)和将入参封装为Map(contextMap)对象。
SqlSourceBuilder和内部类都继承了BaseBuilder表明自己是个解析器并且获得了 typeAliasRegistry、typeHandlerRegistry两个属性 和一些基本的方法。
protected final TypeHandlerRegistry typeHandlerRegistry;
public class SqlSourceBuilder extends BaseBuilder { private static final String parameterProperties = "javaType,jdbcType,mode,numericScale,resultMap,typeHandler,jdbcTypeName"; public SqlSourceBuilder(Configuration configuration) { super(configuration); } public SqlSource parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) { //通过构造一个ParameterMappingTokenHandler和GenericTokenParser解析 originalSql并将originalSql中的#{}替换为? ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters); GenericTokenParser parser = new GenericTokenParser("#{", "}", handler); String sql = parser.parse(originalSql); return new StaticSqlSource(configuration, sql, handler.getParameterMappings()); } private static class ParameterMappingTokenHandler extends BaseBuilder implements TokenHandler { private List<ParameterMapping> parameterMappings = new ArrayList<ParameterMapping>(); private Class<?> parameterType; private MetaObject metaParameters; public ParameterMappingTokenHandler(Configuration configuration, Class<?> parameterType, Map<String, Object> additionalParameters) { super(configuration); this.parameterType = parameterType; //这里在进行newMetaObject的时候additionalParameters已经是一个ContextMap对象 //所以返回的metaParameters中的ObjectWrapper是一个不择不扣的MapWapper //也就是说最后任何对象都会被转换成一个MappWapper this.metaParameters = configuration.newMetaObject(additionalParameters); } public List<ParameterMapping> getParameterMappings() { return parameterMappings; } @Override public String handleToken(String content) { //生成ParameterMapping parameterMappings.add(buildParameterMapping(content)); return "?"; } private ParameterMapping buildParameterMapping(String content) { //ParameterExpression.parse方法会解析content中是否还有其他表达式, //最终生成 propertiesMap property->#{}中包含的值 如 property->id //和其他表达式或者jdbc和ojdbc之间的映射 Map<String, String> propertiesMap = parseParameterMapping(content); String property = propertiesMap.get("property"); Class<?> propertyType; if (metaParameters.hasGetter(property)) { // issue #448 get type from additional params propertyType = metaParameters.getGetterType(property); } else if (typeHandlerRegistry.hasTypeHandler(parameterType)) { propertyType = parameterType; } else if (JdbcType.CURSOR.name().equals(propertiesMap.get("jdbcType"))) { propertyType = java.sql.ResultSet.class; } else if (property == null || Map.class.isAssignableFrom(parameterType)) { propertyType = Object.class; } else { //这里通过寻找参数类型中是否有对应的属性,有则propertyType被设置为相应的类型 MetaClass metaClass = MetaClass.forClass(parameterType, configuration.getReflectorFactory()); if (metaClass.hasGetter(property)) { propertyType = metaClass.getGetterType(property); } else { propertyType = Object.class; } } ParameterMapping.Builder builder = new ParameterMapping.Builder(configuration, property, propertyType); Class<?> javaType = propertyType; String typeHandlerAlias = null; //检查是否有Java类型和jdbc类型的映射 for (Map.Entry<String, String> entry : propertiesMap.entrySet()) { String name = entry.getKey(); String value = entry.getValue(); if ("javaType".equals(name)) { javaType = resolveClass(value); builder.javaType(javaType); } else if ("jdbcType".equals(name)) { builder.jdbcType(resolveJdbcType(value)); } else if ("mode".equals(name)) { builder.mode(resolveParameterMode(value)); } else if ("numericScale".equals(name)) { builder.numericScale(Integer.valueOf(value)); } else if ("resultMap".equals(name)) { builder.resultMapId(value); } else if ("typeHandler".equals(name)) { typeHandlerAlias = value; } else if ("jdbcTypeName".equals(name)) { builder.jdbcTypeName(value); } else if ("property".equals(name)) { // Do Nothing } else if ("expression".equals(name)) { throw new BuilderException("Expression based parameters are not supported yet"); } else { throw new BuilderException("An invalid property '" + name + "' was found in mapping #{" + content + "}. Valid properties are " + parameterProperties); } } if (typeHandlerAlias != null) { //有则为parameterMapping设置相应的类型处理器 builder.typeHandler(resolveTypeHandler(javaType, typeHandlerAlias)); } //构建ParameterMapping return builder.build(); } private Map<String, String> parseParameterMapping(String content) { try { return new ParameterExpression(content); } catch (BuilderException ex) { throw ex; } catch (Exception ex) { throw new BuilderException("Parsing error was found in mapping #{" + content + "}. Check syntax #{property|(expression), var1=value1, var2=value2, ...} ", ex); } } } }
ParameterMapping://TODO
继续执行SqlSourceBuilder#parse,生成StaticSqlSource,
new StaticSqlSource(configuration, sql, handler.getParameterMappings());
public class StaticSqlSource implements SqlSource { private final String sql; private final List<ParameterMapping> parameterMappings; private final Configuration configuration; public StaticSqlSource(Configuration configuration, String sql) { this(configuration, sql, null); } public StaticSqlSource(Configuration configuration, String sql, List<ParameterMapping> parameterMappings) { this.sql = sql; this.parameterMappings = parameterMappings; this.configuration = configuration; } @Override public BoundSql getBoundSql(Object parameterObject) { return new BoundSql(configuration, sql, parameterMappings, parameterObject); } }
BoundSql:
public class BoundSql { private final String sql; private final List<ParameterMapping> parameterMappings; private final Object parameterObject; private final Map<String, Object> additionalParameters; private final MetaObject metaParameters; public BoundSql(Configuration configuration, String sql, List<ParameterMapping> parameterMappings, Object parameterObject) { this.sql = sql; this.parameterMappings = parameterMappings; this.parameterObject = parameterObject; this.additionalParameters = new HashMap<String, Object>(); this.metaParameters = configuration.newMetaObject(additionalParameters); } public String getSql() { return sql; } public List<ParameterMapping> getParameterMappings() { return parameterMappings; } public Object getParameterObject() { return parameterObject; } public boolean hasAdditionalParameter(String name) { String paramName = new PropertyTokenizer(name).getName(); return additionalParameters.containsKey(paramName); } public void setAdditionalParameter(String name, Object value) { metaParameters.setValue(name, value); } public Object getAdditionalParameter(String name) { return metaParameters.getValue(name); } }
观察BoundSql和StaticSqlSource,发现BoundSql只比StaticSqlSource多了metaParameters的参数。
执行到这里不妨总结一下Sql解析的流程和使用到的几个核心类、接口:
在mapper解析阶段XMLScriptBuilder#parseDynamicTags生成MixedSqlNode和
parseScriptNode生成DynamicSqlSource组装生成MappedStatement,执行时传入参数并执行DynamicSqlSource中rootSqlNode最终生成静态的StaticSqlSource,静态的StaticSqlSource是已经解析成jdbc驱动可以执行的语句,进一步加上入参对象封装而成的MetaObject成了BoundSql。
SqlNode接口:表示每个sql片段,有两种实现类,动态:的有if where 等和静态的sql片段,表示不含表达式的sql语句。此接口只包含一个方法,此方法入参为DynamicContext,每次调用判断将sql追加到上下文的末尾,形成整个一个语句。各种SqlNode在XMLScriptBuilder#parseDynamicTags被创建加入一个MixedSqlNode中,MapperStatement的rootSqlNode执行apply后销亡。
ParameterMapping:包含当前#{}中包含的参数对象类型的属性名称、类型等,执行阶段被ParameterMappingTokenHandler#buildParameterMapping或者MapperBuilderAssistant#buildParameterMapping生成,并加入SqlSource
SqlSource:在动态的SqlSource包含SqlNode的实例,静态SqlSource包含解析后的sql和参数映射ParameterMapping,DynamicSqlSource在解析阶段使用,StaticSqlSource在执行阶段使用。
BoundSql:包含静态sql语句,ParameterMapping参数映射,parameterObject原生传入参数,additionalParameters额外的参数( DynamicContext中所有的值)以及metaParameters,额外参数对应的获取方法,BoundSql包含了一个sql得以执行的所有必需条件。
继续执行MapperStatement#getBoundSql
到此MapperStatement的getBoundSql就执行完成了
发表评论
-
MyBatis原理(2)-执行流程 4 Mapper的执行
2018-09-07 11:15 762执行方式2: DeptMapper mapper ... -
MyBatis原理(2)-执行流程 3 处理结果集
2018-09-07 10:24 871DefaultResultSetHandler#handleR ... -
MyBatis原理(2)-执行流程 2
2018-08-31 17:47 546@Override public <E> L ... -
MyBatis原理(1)-启动流程3- mapper 加载
2018-08-25 22:27 8611.接着上一篇文章解析mapper第一步 mapperEle ... -
MyBatis原理(1)-启动流程2
2018-08-24 17:21 5541.XMLConfigBuilder.parse ... -
MyBatis原理(1)-启动流程1
2018-08-23 17:10 1141概述:本文按三个部分依次循序渐进对mybatis源码-原理进行 ...
相关推荐
mybatis-plus最新代码生成器项目源码 :mybatis-plus-generator.zip mybatis-plus最新代码生成器项目源码 :mybatis-plus-generator.zip mybatis-plus最新代码生成器项目源码 :mybatis-plus-generator.zip ...
mybatis-generator-config_1_0.dtd文件存在于mybatis-generator-core-1.3.2.jar包中,路径如下org/mybatis/generator/config/xml/mybatis-generator-config_1_0.dtd 可以设置开发工具的dtd配置,配置...
mybatis-plus-sample-generator: 代码生成器示例 mybatis-plus-sample-crud: 完整 CRUD 示例 mybatis-plus-sample-wrapper: 条件构造器示例 mybatis-plus-sample-pagination: 分页功能示例 mybatis-plus-sample-...
在MyBatis中,`mybatis-3-config.dtd` 和 `mybatis-3-mapper.dtd` 是两个至关重要的DTD(Document Type Definition)文件,它们定义了MyBatis配置文件和映射文件的结构和规则。 首先,让我们深入了解一下`mybatis-3...
【标题】"mybatis-generator-1.3.2 代码生成" 涉及到的是一个基于MyBatis框架的代码生成工具,主要用于自动化地创建MyBatis的SQL映射文件、Mapper接口、Mapper XML文件以及实体类。这个工具极大地提高了开发效率,...
然后打开eclipse ->Window->prefenrence->XML->XML Catalog->User Specifiled Entreis->Add->Location(此处是你放dtd文件的位置例如:D:\mybatis\mybatis-3-config.dtd)->Key(如果更改config,此处应该是:-//...
总的来说,`mybatis-generator-core-1.4.0-bundle.zip` 是一个方便的工具,可以帮助开发者快速生成与数据库交互的 MyBatis 代码,简化开发流程,提高代码质量。在实际开发中,结合合适的配置和定制模板,可以进一步...
总的来说,mybatis-generator-gui是一个便捷的开发工具,通过图形界面简化了MyBatis的Mapper文件生成过程,提高了开发效率,同时提供了数据库类的自动生成功能,使开发者能更专注于业务逻辑的实现。对于使用MyBatis...
mybatis-plus-generato.jar 包,各个版本,免费下载。 mybatis-plus 代码生成器生成代码框架。各个版本,免费下载。 下载不了,关注我,评论区联系我。
使用命令行直接执行,java -jar mybatis-generator-core-1.3.6.jar -configfile generatorConfig.xml -overwrite 包含mybatis-generator-core-1.3.6.zip代码自动生成器官方最新版本的jar包、mysql数据库连接jar包、...
mybatis-plus-generato.jar 包,各个版本,免费下载。 mybatis-plus 代码生成器生成代码框架。各个版本,免费下载。 下载不了,关注我,评论区联系我。
利用mybatis-generator-core可以自动生成实体类、dao接口和mapping映射文件,里头也提供了使用说明: 1、进入lib文件夹里头。 2、修改generatorConfig.xml配置 主要修改数据库地址,用户名,密码,以及数据库名称,...
1. **下载源码**:首先,你需要下载`mybatis-generator-core-1.3.2`的源代码,这通常可以从MyBatis的官方网站或者GitHub仓库获取。 2. **理解源码结构**:MBG的核心在于`org.mybatis.generator.api`包,其中`...
为了在项目中快捷方便的代码生成,将mybatis-plus-generator封装为了一个maven的插件`mybatis-plus-generator-maven-plugin。使用文档参考:https://blog.csdn.net/xiweiller/article/details/103072165
mybatis-generator-gui自动生成代码的工具,但是jdk必须大于1.8
8. **Maven集成**:在大型项目中,通常会将MyBatis Generator集成到Maven或Gradle构建系统中,通过执行特定的目标或任务来自动化代码生成,确保每次构建时都能得到最新的代码。 9. **性能优化**:虽然MyBatis ...
总之,`mybatis-generator-gui-plus`是提升MyBatis开发效率的重要工具,它通过图形化的操作界面简化了代码生成流程,降低了开发难度,让开发者能够更专注于业务逻辑的实现,从而提高整体项目的开发质量和速度。...
1. `mybatis-generator-core-1.3.2.jar`:MBG 的核心库,包含所有实现代码生成功能的类和接口。 2. `lib` 目录:可能包含 MBG 运行时依赖的第三方库,如 JDBC 驱动等。 3. `README` 或 `doc` 文件:提供关于如何使用...
下面将详细介绍MyBatis-Spring的主要功能、工作原理以及如何与MyBatis-3.4.4等版本配合使用。 MyBatis-Spring的主要功能: 1. **自动扫描与配置**:MyBatis-Spring能够自动扫描项目中的Mapper接口,并根据这些接口...
mybatis-spring-2.0.6.jar