- 浏览: 14624 次
- 性别:
- 来自: 成都
-
最新评论
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 778执行方式2: DeptMapper mapper ... -
MyBatis原理(2)-执行流程 3 处理结果集
2018-09-07 10:24 887DefaultResultSetHandler#handleR ... -
MyBatis原理(2)-执行流程 2
2018-08-31 17:47 566@Override public <E> L ... -
MyBatis原理(1)-启动流程3- mapper 加载
2018-08-25 22:27 8821.接着上一篇文章解析mapper第一步 mapperEle ... -
MyBatis原理(1)-启动流程2
2018-08-24 17:21 5721.XMLConfigBuilder.parse ... -
MyBatis原理(1)-启动流程1
2018-08-23 17:10 1163概述:本文按三个部分依次循序渐进对mybatis源码-原理进行 ...
相关推荐
#### 四、MyBatis执行流程 ##### 4.1 获取SqlSession 在实际应用中,我们通常通过`SqlSessionFactory.openSession()`方法获取一个`SqlSession`实例。该方法会创建一个新的`SqlSession`并返回给调用者。 ##### 4.2...
1. **初始化过程**:了解MyBatis的初始化流程,包括SqlSessionFactoryBuilder的创建、SqlSessionFactory的构建,以及Configuration类中加载XML配置文件的过程。 2. **SQL执行**:研究Executor接口及其实现,如...
通过阅读源码,开发者可以深入理解MyBatis的工作原理,学习如何设计和实现一个高效的ORM框架,以及如何处理SQL语句的动态生成与执行。 描述中提到的"Eclipse中点击Open Source导入源码",意味着我们可以使用Eclipse...
内容概要:本文档《数据结构》(02331)第一章主要介绍数据结构的基础概念,涵盖数据与数据元素的定义及其特性,详细阐述了数据结构的三大要素:逻辑结构、存储结构和数据运算。逻辑结构分为线性结构(如线性表、栈、队列)、树形结构(涉及根节点、父节点、子节点等术语)和其他结构。存储结构对比了顺序存储和链式存储的特点,包括访问方式、插入删除操作的时间复杂度以及空间分配方式,并介绍了索引存储和散列存储的概念。最后讲解了抽象数据类型(ADT)的定义及其组成部分,并探讨了算法分析中的时间复杂度计算方法。 适合人群:计算机相关专业学生或初学者,对数据结构有一定兴趣并希望系统学习其基础知识的人群。 使用场景及目标:①理解数据结构的基本概念,掌握逻辑结构和存储结构的区别与联系;②熟悉不同存储方式的特点及应用场景;③学会分析简单算法的时间复杂度,为后续深入学习打下坚实基础。 阅读建议:本章节内容较为理论化,建议结合实际案例进行理解,尤其是对于逻辑结构和存储结构的理解要深入到具体的应用场景中,同时可以尝试编写一些简单的程序来加深对抽象数据类型的认识。
内容概要:本文详细介绍了施耐德M580系列PLC的存储结构、系统硬件架构、上电写入程序及CPU冗余特性。在存储结构方面,涵盖拓扑寻址、Device DDT远程寻址以及寄存器寻址三种方式,详细解释了不同类型的寻址方法及其应用场景。系统硬件架构部分,阐述了最小系统的构建要素,包括CPU、机架和模块的选择与配置,并介绍了常见的系统拓扑结构,如简单的机架间拓扑和远程子站以太网菊花链等。上电写入程序环节,说明了通过USB和以太网两种接口进行程序下载的具体步骤,特别是针对初次下载时IP地址的设置方法。最后,CPU冗余部分重点描述了热备功能的实现机制,包括IP通讯地址配置和热备拓扑结构。 适合人群:从事工业自动化领域工作的技术人员,特别是对PLC编程及系统集成有一定了解的工程师。 使用场景及目标:①帮助工程师理解施耐德M580系列PLC的寻址机制,以便更好地进行模块配置和编程;②指导工程师完成最小系统的搭建,优化系统拓扑结构的设计;③提供详细的上电写入程序指南,确保程序下载顺利进行;④解释CPU冗余的实现方式,提高系统的稳定性和可靠性。 其他说明:文中还涉及一些特殊模块的功能介绍,如定时器事件和Modbus串口通讯模块,这些内容有助于用户深入了解M580系列PLC的高级应用。此外,附录部分提供了远程子站和热备冗余系统的实物图片,便于用户直观理解相关概念。
某型自动垂直提升仓储系统方案论证及关键零部件的设计.zip
2135D3F1EFA99CB590678658F575DB23.pdf#page=1&view=fitH
可以搜索文本内的内容,指定目录,指定文件格式,匹配大小写等
Windows 平台 Android Studio 下载与安装指南.zip
Android Studio Meerkat 2024.3.1 Patch 1(android-studio-2024.3.1.14-windows.zip)适用于Windows系统,文件使用360压缩软件分割成两个压缩包,必须一起下载使用: part1: https://download.csdn.net/download/weixin_43800734/90557033 part2: https://download.csdn.net/download/weixin_43800734/90557035
国网台区终端最新规范
国网台区终端最新规范
1.【锂电池剩余寿命预测】Transformer-GRU锂电池剩余寿命预测(Matlab完整源码和数据) 2.数据集:NASA数据集,已经处理好,B0005电池训练、B0006测试; 3.环境准备:Matlab2023b,可读性强; 4.模型描述:Transformer-GRU在各种各样的问题上表现非常出色,现在被广泛使用。 5.领域描述:近年来,随着锂离子电池的能量密度、功率密度逐渐提升,其安全性能与剩余使用寿命预测变得愈发重要。本代码实现了Transformer-GRU在该领域的应用。 6.作者介绍:机器学习之心,博客专家认证,机器学习领域创作者,2023博客之星TOP50,主做机器学习和深度学习时序、回归、分类、聚类和降维等程序设计和案例分析,文章底部有博主联系方式。从事Matlab、Python算法仿真工作8年,更多仿真源码、数据集定制私信。
Android项目原生java语言课程设计,包含LW+ppt
大学生入门前端-五子棋vue项目
这是一个完整的端到端解决方案,用于分析和预测阿联酋(UAE)地区的二手车价格。数据集包含 10,000 条二手车信息,覆盖了迪拜、阿布扎比和沙迦等城市,并提供了精确的地理位置数据。此外,项目还包括一个基于 Dash 构建的 Web 应用程序代码和一个训练好的 XGBoost 模型,帮助用户探索区域市场趋势、预测车价以及可视化地理空间洞察。 数据集内容 项目文件以压缩 ZIP 归档形式提供,包含以下内容: 数据文件: data/uae_used_cars_10k.csv:包含 10,000 条二手车记录的数据集,涵盖车辆品牌、型号、年份、里程数、发动机缸数、价格、变速箱类型、燃料类型、颜色、描述以及销售地点(如迪拜、阿布扎比、沙迦)。 模型文件: models/stacking_model.pkl:训练好的 XGBoost 模型,用于预测二手车价格。 models/scaler.pkl:用于数据预处理的缩放器。 models.py:模型相关功能的实现。 train_model.py:训练模型的脚本。 Web 应用程序文件: app.py:Dash 应用程序的主文件。 callback
资源内项目源码是来自个人的毕业设计,代码都测试ok,包含源码、数据集、可视化页面和部署说明,可产生核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果、标签分布图。都是运行成功后才上传资源,毕设答辩评审绝对信服的保底85分以上,放心下载使用,拿来就能用。包含源码、数据集、可视化页面和部署说明一站式服务,拿来就能用的绝对好资源!!! 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、大作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.txt文件,仅供学习参考, 切勿用于商业用途。
资源内项目源码是来自个人的毕业设计,代码都测试ok,包含源码、数据集、可视化页面和部署说明,可产生核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果、标签分布图。都是运行成功后才上传资源,毕设答辩评审绝对信服的保底85分以上,放心下载使用,拿来就能用。包含源码、数据集、可视化页面和部署说明一站式服务,拿来就能用的绝对好资源!!! 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、大作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.txt文件,仅供学习参考, 切勿用于商业用途。
此为代码审查工具 可查 文件数,字节数,总行数,代码行数,注释行数,空白行数,注释率等