1.入口
public static void main(String[] args) {
//获取配置文件信息流
InputStream stream = Demo.class.getClassLoader().getResourceAsStream("mybatis.xml");
//使用SqlSessionFactory构建器,读取配置文件构建出一个sessionFactory
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(stream);
//通过sessionFactory开启一个Session
SqlSession sqlSession = sessionFactory.openSession(true);
//调用selectOne方法查询数据
User user = sqlSession.selectOne("org.demo.bean.UserMapper.getUser", 1);
//输出
System.out.println(user);
}
2.使用SqlSessionFactory构建器,读取配置文件构建出一个sessionFactory
/**
* 读取配置文件流 构建一个
* @param inputStream 配置文件流
*/
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
//1.根据配置文件信息流,生成一个XMLConfigBuilder
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//2.构建SqlSessionFactory并返回
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
}
}
}
2.1 XMLConfigBuilder的创建
/**
* 构建XMLConfigBuilder对象
*/
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
//创建一个Configuration并调用父类构造方法进行赋值
super(new Configuration());
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props);
this.parsed = false;
this.environment = environment;
this.parser = parser;
}
其中XPathParser对象构造函数如下
/**
* 构建XPathParser对象
*/
public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
//1.赋值
commonConstructor(validation, variables, entityResolver);
//2.读取配置文件信息流构建document 并记录到XPathParser对象中
this.document = createDocument(new InputSource(inputStream));
}
/**
* 赋值
*/
private void commonConstructor(boolean validation, Properties variables, EntityResolver entityResolver) {
this.validation = validation;
this.entityResolver = entityResolver;
this.variables = variables;
XPathFactory factory = XPathFactory.newInstance();
this.xpath = factory.newXPath();
}
这里将配置文件构建成一个document对象赋值到XPathParser对象的XPathParser中
2.构建SqlSessionFactory
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
//1.根据配置文件信息流,生成一个XMLConfigBuilder
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//2.根据parser构建SqlSessionFactory并返回
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
}
}
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
这里是直接根据Configuration创建一个DefaultSqlSessionFactory对象进行返回。这里我们看一下Configuration对象的形成是再parser.parse()方法返回的。
public Configuration parse() {
//用parsed保证方法只会执行一次
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true; //修改为true 不会多次执行
//
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
private void parseConfiguration(XNode root) {
try {
propertiesElement(root.evalNode("properties"));
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
loadCustomLogImpl(settings);
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
settingsElement(settings);
//解析environments节点信息
environmentsElement(root.evalNode("environments"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
//解析mapper节点信息
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
由上可知,parse方法只会执行一次,parseConfiguration是读取配置文件中的各个节点信息,根据节点信息进行处理,这些节点读取的顺序是不可以改变的。
2.1 environmentsElement节点信息解析
/**
* 解析environments节点信息
*/
private void environmentsElement(XNode context) throws Exception {
if (context != null) {
if (environment == null) {
environment = context.getStringAttribute("default");
}
for (XNode child : context.getChildren()) {
String id = child.getStringAttribute("id");
if (isSpecifiedEnvironment(id)) {
TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
//解析dataSource节点 生成DataSourceFactory
DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
//构建数据源DataSource
DataSource dataSource = dsFactory.getDataSource();
//创建Environment.Builder构建器并设置txFactory与dataSource的信息
Environment.Builder environmentBuilder = new Environment.Builder(id)
.transactionFactory(txFactory)
.dataSource(dataSource);
//利用构建器构建一个Environment设置到configuration中
configuration.setEnvironment(environmentBuilder.build());
}
}
}
}
/**
* 根据context内容构建数据源工厂
*/
private DataSourceFactory dataSourceElement(XNode context) throws Exception {
if (context != null) {
//获取type节点信息
String type = context.getStringAttribute("type");
//封装子节点信息
Properties props = context.getChildrenAsProperties();
//创建数据源工厂
DataSourceFactory factory = (DataSourceFactory) resolveClass(type).getDeclaredConstructor().newInstance();
//设置props
factory.setProperties(props);
return factory; //返回
}
throw new BuilderException("Environment declaration requires a DataSourceFactory.");
}
这里不做详细解释了,根据节点信息生成对应工厂,最后将信息配置到configuration对象中下面看一下mappers节点解析吧
2.2 mappers节点解析
/**
* 解析mapper节点信息
*/
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
//package 形式配置
if ("package".equals(child.getName())) {
//获取配置的name
String mapperPackage = child.getStringAttribute("name");
//添加到configuration中的mapperRegistry中
//这里会遍历package下的所有类进行处理
configuration.addMappers(mapperPackage);
} else {
//获取resource,url,class
String resource = child.getStringAttribute("resource");
String url = child.getStringAttribute("url");
String mapperClass = child.getStringAttribute("class");
if (resource != null && url == null && mapperClass == null) {
//当且仅当resource不为null时
ErrorContext.instance().resource(resource);
//获取resource对应配置文件信息
InputStream inputStream = Resources.getResourceAsStream(resource);
//根据resource配置信息生成XMLMapperBuilder
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
//调用parse方法处理
mapperParser.parse();
} else if (resource == null && url != null && mapperClass == null) {
//当且仅当url不为null时
ErrorContext.instance().resource(url);
InputStream inputStream = Resources.getUrlAsStream(url);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
mapperParser.parse();
} else if (resource == null && url == null && mapperClass != null) {
//当且仅当mapperClass不为null时
//根据配置mapperClass获取class对象
Class<?> mapperInterface = Resources.classForName(mapperClass);
//添加到configuration
configuration.addMapper(mapperInterface);
} else { //没有进行配置或配置了多个都直接抛出异常
throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
}
}
}
}
}
猛的一看,这if else看的让人头大有没有?仔细一看其实也没有什么特别难理解的逻辑,这里先判断是否为package配置,然后进行处理,否则就根据resource,url,class的配置进行不同处理,这里的三个参数只有配置一个的时候生效,不配置或者配置多个都不生效。
package 形式配置代码
/**
* 添加packageName到mapperRegistry中
*/
public void addMappers(String packageName) {
mapperRegistry.addMappers(packageName);
}
/**
* 根据packageName添加mapper
* @since 3.2.2
*/
public void addMappers(String packageName) {
addMappers(packageName, Object.class);
}
/**
* 根据packageName添加mapper
* @since 3.2.2
*/
public void addMappers(String packageName, Class<?> superType) {
//创建ResolverUtil对象
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
//调用resolverUtil的find方法进行处理
//这里会用ResolverUtil.IsA来保存superType信息
resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
//获取mapperset
Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();
for (Class<?> mapperClass : mapperSet) {
//调用addMapper处理
addMapper(mapperClass);
}
}
/**
* 添加mapper的class
*/
public <T> void addMapper(Class<T> type) {
if (type.isInterface()) { //必须时接口文件才进行处理
if (hasMapper(type)) { //是否已存在 若存在则可能存在重复配置 是不被允许的 直接抛出异常
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
boolean loadCompleted = false;
try {
//添加到knownMappers中 这是一个HashMap
//MapperProxyFactory是Mapper接口对应的代理工厂
knownMappers.put(type, new MapperProxyFactory<>(type));
//根据config和type程间MapperAnnotationBuilder构造器
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
//处理
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
knownMappers.remove(type);
}
}
}
}
从代码可知,这里会解析package路径下每个接口,对每个类生成一个创建一个代理对象工厂,注意,是代理对象的工厂,并未生成对应的代理对象,工厂生成之后创建了一个MapperAnnotationBuilder构造器,并调用了其parse方法,下面我们来看一下这个方法
/**
* 解析mapper
*/
public void parse() {
//获取type的字符串形式 type是class类型
String resource = type.toString();
//判断resource是否已经加载过
//这里用configuration中的loadedResources来记录已加载过的,防止重复加载
if (!configuration.isResourceLoaded(resource)) {
//加载mapper对应的xml路径
loadXmlResource();
//添加resource到configuration中的loadedResources
configuration.addLoadedResource(resource);
//设置命名空间
assistant.setCurrentNamespace(type.getName());
//处理CacheNamespace注解
parseCache();
//处理CacheNamespaceRef注解
parseCacheRef();
//获取type中所有方法进行遍历
Method[] methods = type.getMethods();
for (Method method : methods) {
try {
if (!method.isBridge()) {
//方法处理
parseStatement(method);
}
} catch (IncompleteElementException e) {
configuration.addIncompleteMethod(new MethodResolver(this, method));
}
}
}
parsePendingMethods();
}
这里会加载mapper的信息,并遍历其中每一个方法进行parseStatement处理
loadXmlResource()方法处理
/**
* 加载xml路径
*/
private void loadXmlResource() {
//校验是否已经加载过
if (!configuration.isResourceLoaded("namespace:" + type.getName())) {
//获取对应的xml文件名
String xmlResource = type.getName().replace('.', '/') + ".xml";
//获取文件流
InputStream inputStream = type.getResourceAsStream("/" + xmlResource);
if (inputStream == null) {
// Search XML mapper that is not in the module but in the classpath.
try {
inputStream = Resources.getResourceAsStream(type.getClassLoader(), xmlResource);
} catch (IOException e2) {
// ignore, resource is not required
}
}
if (inputStream != null) {
//创建XMLMapperBuilder解析inputStream中的信息
XMLMapperBuilder xmlParser = new XMLMapperBuilder(inputStream, assistant.getConfiguration(), xmlResource, configuration.getSqlFragments(), type.getName());
xmlParser.parse();
}
}
}
/**
* 处理mapper的xml文件
*/
public void parse() {
//是否加载过
if (!configuration.isResourceLoaded(resource)) {
//解析mapper
configurationElement(parser.evalNode("/mapper"));
//添加resource到configuration的loadedResources中
configuration.addLoadedResource(resource);
//通过命名空间绑定mapper
bindMapperForNamespace();
}
//解析ResultMap
parsePendingResultMaps();
//解析CacheRef
parsePendingCacheRefs();
//解析Statement
parsePendingStatements();
}
private void configurationElement(XNode context) {
try {
//获取命名空间namespace
String namespace = context.getStringAttribute("namespace");
if (namespace == null || namespace.equals("")) { //校验
throw new BuilderException("Mapper's namespace cannot be empty");
}
builderAssistant.setCurrentNamespace(namespace);
//缓存cache-ref节点信息 hashMap
cacheRefElement(context.evalNode("cache-ref"));
//开启二级缓存,相关处理
cacheElement(context.evalNode("cache"));
//解析parameterMap
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
//解析resultMap
resultMapElements(context.evalNodes("/mapper/resultMap"));
//解析并缓存sql节点信息
sqlElement(context.evalNodes("/mapper/sql"));
//解析每个select|insert|update|delete节点信息
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
} catch (Exception e) {
throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);
}
}
这里会解析接口对应的xml文件,解析每个标签,对每个select|insert|update|delete节点处理代码如下
/**
* 解析mapper.xml中的增删改查节点
*/
private void buildStatementFromContext(List<XNode> list) {
if (configuration.getDatabaseId() != null) {
buildStatementFromContext(list, configuration.getDatabaseId());
}
buildStatementFromContext(list, null);
}
/**
* 解析mapper.xml中的增删改查节点
*/
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
for (XNode context : list) {
//生成XMLStatementBuilder构建器
final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
try {
//构建
statementParser.parseStatementNode();
} catch (IncompleteElementException e) {
configuration.addIncompleteStatement(statementParser);
}
}
}
public void parseStatementNode() {
//获取节点的各个属性
String id = context.getStringAttribute("id");
String databaseId = context.getStringAttribute("databaseId");
if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
return;
}
String nodeName = context.getNode().getNodeName();
SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
boolean useCache = context.getBooleanAttribute("useCache", isSelect);
boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);
XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
includeParser.applyIncludes(context.getNode());
String parameterType = context.getStringAttribute("parameterType");
Class<?> parameterTypeClass = resolveClass(parameterType);
String lang = context.getStringAttribute("lang");
LanguageDriver langDriver = getLanguageDriver(lang);
processSelectKeyNodes(id, parameterTypeClass, langDriver);
KeyGenerator keyGenerator;
String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);
if (configuration.hasKeyGenerator(keyStatementId)) {
keyGenerator = configuration.getKeyGenerator(keyStatementId);
} else {
keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
}
SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
Integer fetchSize = context.getIntAttribute("fetchSize");
Integer timeout = context.getIntAttribute("timeout");
String parameterMap = context.getStringAttribute("parameterMap");
String resultType = context.getStringAttribute("resultType");
Class<?> resultTypeClass = resolveClass(resultType);
String resultMap = context.getStringAttribute("resultMap");
String resultSetType = context.getStringAttribute("resultSetType");
ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);
if (resultSetTypeEnum == null) {
resultSetTypeEnum = configuration.getDefaultResultSetType();
}
String keyProperty = context.getStringAttribute("keyProperty");
String keyColumn = context.getStringAttribute("keyColumn");
String resultSets = context.getStringAttribute("resultSets");
//根据节点信息构建MappedStatement
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
addMappedStatement方法
public MappedStatement addMappedStatement(
String id,
SqlSource sqlSource,
StatementType statementType,
SqlCommandType sqlCommandType,
Integer fetchSize,
Integer timeout,
String parameterMap,
Class<?> parameterType,
String resultMap,
Class<?> resultType,
ResultSetType resultSetType,
boolean flushCache,
boolean useCache,
boolean resultOrdered,
KeyGenerator keyGenerator,
String keyProperty,
String keyColumn,
String databaseId,
LanguageDriver lang,
String resultSets) {
if (unresolvedCacheRef) {
throw new IncompleteElementException("Cache-ref not yet resolved");
}
id = applyCurrentNamespace(id, false);
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType)
.resource(resource)
.fetchSize(fetchSize)
.timeout(timeout)
.statementType(statementType)
.keyGenerator(keyGenerator)
.keyProperty(keyProperty)
.keyColumn(keyColumn)
.databaseId(databaseId)
.lang(lang)
.resultOrdered(resultOrdered)
.resultSets(resultSets)
.resultMaps(getStatementResultMaps(resultMap, resultType, id))
.resultSetType(resultSetType)
.flushCacheRequired(valueOrDefault(flushCache, !isSelect))
.useCache(valueOrDefault(useCache, isSelect))
.cache(currentCache);
ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id);
if (statementParameterMap != null) {
statementBuilder.parameterMap(statementParameterMap);
}
MappedStatement statement = statementBuilder.build();
configuration.addMappedStatement(statement);
return statement;
}
然后我们回来看一下parseStatement方法得处理
/**
* 解析mapper中的方法
*/
void parseStatement(Method method) {
//获取参数类型
Class<?> parameterTypeClass = getParameterType(method);
//获取语言驱动器
LanguageDriver languageDriver = getLanguageDriver(method);
//获取方法的SqlSource对象,只有指定了@Select/@Insert/@Update/@Delete或者对应的Provider的方法才会被当作mapper,否则只是和mapper文件中对应语句的一个运行时占位符
SqlSource sqlSource = getSqlSourceFromAnnotations(method, parameterTypeClass, languageDriver);
if (sqlSource != null) {
//获取方法的属性设置,对应<select>中的各种属性
Options options = method.getAnnotation(Options.class);
final String mappedStatementId = type.getName() + "." + method.getName();
Integer fetchSize = null;
Integer timeout = null;
StatementType statementType = StatementType.PREPARED;
ResultSetType resultSetType = configuration.getDefaultResultSetType();
//获取语句的CRUD类型
SqlCommandType sqlCommandType = getSqlCommandType(method);
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
boolean flushCache = !isSelect;
boolean useCache = isSelect;
KeyGenerator keyGenerator;
String keyProperty = null;
String keyColumn = null;
//只有INSERT/UPDATE才解析SelectKey选项
if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) {
SelectKey selectKey = method.getAnnotation(SelectKey.class);
if (selectKey != null) {
keyGenerator = handleSelectKeyAnnotation(selectKey, mappedStatementId, getParameterType(method), languageDriver);
keyProperty = selectKey.keyProperty();
} else if (options == null) {
keyGenerator = configuration.isUseGeneratedKeys() ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
} else {
keyGenerator = options.useGeneratedKeys() ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
keyProperty = options.keyProperty();
keyColumn = options.keyColumn();
}
} else {
keyGenerator = NoKeyGenerator.INSTANCE;
}
if (options != null) {
if (FlushCachePolicy.TRUE.equals(options.flushCache())) {
flushCache = true;
} else if (FlushCachePolicy.FALSE.equals(options.flushCache())) {
flushCache = false;
}
useCache = options.useCache();
fetchSize = options.fetchSize() > -1 || options.fetchSize() == Integer.MIN_VALUE ? options.fetchSize() : null; //issue #348
timeout = options.timeout() > -1 ? options.timeout() : null;
statementType = options.statementType();
if (options.resultSetType() != ResultSetType.DEFAULT) {
resultSetType = options.resultSetType();
}
}
String resultMapId = null;
//解析@ResultMap注解,如果有@ResultMap注解,就是用它,否则才解析@Results
//@ResultMap注解用于给@Select和@SelectProvider注解提供在xml配置的<resultMap>,如果一个方法上同时出现@Results或者@ConstructorArgs等和结果映射有关的注解,那么@ResultMap会覆盖后面两者的注解
ResultMap resultMapAnnotation = method.getAnnotation(ResultMap.class);
if (resultMapAnnotation != null) {
resultMapId = String.join(",", resultMapAnnotation.value());
} else if (isSelect) {
//如果是查询,且没有明确设置ResultMap,则根据返回类型自动解析生成ResultMap
resultMapId = parseResultMap(method);
}
assistant.addMappedStatement(
mappedStatementId,
sqlSource,
statementType,
sqlCommandType,
fetchSize,
timeout,
// ParameterMapID
null,
parameterTypeClass,
resultMapId,
getReturnType(method),
resultSetType,
flushCache,
useCache,
// TODO gcode issue #577
false,
keyGenerator,
keyProperty,
keyColumn,
// DatabaseID
null,
languageDriver,
// ResultSets
options != null ? nullOrEmpty(options.resultSets()) : null);
}
}
================================================================================================
================================================================================================
总结:
//获取配置文件信息流
InputStream stream = Demo.class.getClassLoader().getResourceAsStream("mybatis.xml");
//使用SqlSessionFactory构建器,读取配置文件构建出一个sessionFactory
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(stream);
这两行代码主要是解析mybatis配置文件,包含配置文件的各种信息,然后把解析到的信息封装到Configuration对象中,然后根据Configuration对象创建一个DefaultSqlSessionFactory对象返回。
最后上一下Configuration类的源码
public class Configuration {
protected Environment environment;
protected boolean safeRowBoundsEnabled;
protected boolean safeResultHandlerEnabled = true;
protected boolean mapUnderscoreToCamelCase;
protected boolean aggressiveLazyLoading;
protected boolean multipleResultSetsEnabled = true;
protected boolean useGeneratedKeys;
protected boolean useColumnLabel = true;
protected boolean cacheEnabled = true;
protected boolean callSettersOnNulls;
protected boolean useActualParamName = true;
protected boolean returnInstanceForEmptyRow;
protected String logPrefix;
protected Class<? extends Log> logImpl;
protected Class<? extends VFS> vfsImpl;
protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;
protected JdbcType jdbcTypeForNull = JdbcType.OTHER;
protected Set<String> lazyLoadTriggerMethods = new HashSet<>(Arrays.asList("equals", "clone", "hashCode", "toString"));
protected Integer defaultStatementTimeout;
protected Integer defaultFetchSize;
protected ResultSetType defaultResultSetType;
protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
protected AutoMappingBehavior autoMappingBehavior = AutoMappingBehavior.PARTIAL;
protected AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior = AutoMappingUnknownColumnBehavior.NONE;
protected Properties variables = new Properties();
protected ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
protected ObjectFactory objectFactory = new DefaultObjectFactory();
protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
protected boolean lazyLoadingEnabled = false;
protected ProxyFactory proxyFactory = new JavassistProxyFactory(); // #224 Using internal Javassist instead of OGNL
protected String databaseId;
/**
* Configuration factory class.
* Used to create Configuration for loading deserialized unread properties.
*
* @see <a href='https://code.google.com/p/mybatis/issues/detail?id=300'>Issue 300 (google code)</a>
*/
protected Class<?> configurationFactory;
protected final MapperRegistry mapperRegistry = new MapperRegistry(this);
protected final InterceptorChain interceptorChain = new InterceptorChain();
protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();
protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();
protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection")
.conflictMessageProducer((savedValue, targetValue) ->
". please check " + savedValue.getResource() + " and " + targetValue.getResource());
protected final Map<String, Cache> caches = new StrictMap<>("Caches collection");
protected final Map<String, ResultMap> resultMaps = new StrictMap<>("Result Maps collection");
protected final Map<String, ParameterMap> parameterMaps = new StrictMap<>("Parameter Maps collection");
protected final Map<String, KeyGenerator> keyGenerators = new StrictMap<>("Key Generators collection");
protected final Set<String> loadedResources = new HashSet<>();
protected final Map<String, XNode> sqlFragments = new StrictMap<>("XML fragments parsed from previous mappers");
protected final Collection<XMLStatementBuilder> incompleteStatements = new LinkedList<>();
protected final Collection<CacheRefResolver> incompleteCacheRefs = new LinkedList<>();
protected final Collection<ResultMapResolver> incompleteResultMaps = new LinkedList<>();
protected final Collection<MethodResolver> incompleteMethods = new LinkedList<>();
/*
* A map holds cache-ref relationship. The key is the namespace that
* references a cache bound to another namespace and the value is the
* namespace which the actual cache is bound to.
*/
protected final Map<String, String> cacheRefMap = new HashMap<>();
public Configuration(Environment environment) {
this();
this.environment = environment;
}
public Configuration() {
typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
typeAliasRegistry.registerAlias("LRU", LruCache.class);
typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
typeAliasRegistry.registerAlias("WEAK", WeakCache.class);
typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);
typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);
typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);
languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
languageRegistry.register(RawLanguageDriver.class);
}
//后面省略--------
}