标签:typeAliasRegistry registerAlias 配置管理 private public Mybatis new class
查找配置文件
Resources
在使用Mybatis的过程中,通常使用Mybatis
的Resources
类读取配置文件。在Mybatis 3.5.1
的API
文档中,对Resources
类的描述如下:
A class to simplify access to resources through the classloader.
即Resources
通过ClassLoader
访问资源。
Resources
类有两个静态属性:classLoaderWrapper
和Charset
。
ClassLoaderWrapper
类是ClassLoader
类的包装类。ClassLoaderWrapper
类有两个属aaaaaaaa性defaultClassLoader
和systemClassLoader
分别存储默认的类加载器和系统类加载器。系统类加载器systemClassLoader
在ClassLoaderWrapper
的构造方法中通过ClassLoader.getSystemClassLoader
方法获取:
ClassLoaderWrapper() {
try {
systemClassLoader = ClassLoader.getSystemClassLoader();
} catch (SecurityException ignored) {
// AccessControlException on Google App Engine
}
}
而defaultClassLoader
值则通过Resources
类的静态方法setDefaultClassLoader
和getDefaultClassLoader
设置和获取。
ClassLoaderWrapper
类中的方法有:
getResourceAsURL
getResourceAsStream
classForName
每个方法都被重载,参数分别为资源路径;资源路径,类加载器;资源路径,类加载器数组。
而前两种重载都调用了第三种重载,以getResourceAsURL
为例:
public URL getResourceAsURL(String resource) {
return getResourceAsURL(resource, getClassLoaders(null));
}
public URL getResourceAsURL(String resource, ClassLoader classLoader) {
return getResourceAsURL(resource, getClassLoaders(classLoader));
}
URL getResourceAsURL(String resource, ClassLoader[] classLoader) {
URL url;
for (ClassLoader cl : classLoader) {
if (null != cl) {
// look for the resource as passed in...
url = cl.getResource(resource);
// ...but some class loaders want this leading "/", so we'll add it
// and try again if we didn't find the resource
if (null == url) {
url = cl.getResource("/" + resource);
}
// "It's always in the last place I look for it!"
// ... because only an idiot would keep looking for it after finding it, so stop looking already.
if (null != url) {
return url;
}
}
}
// didn't find it anywhere.
return null;
}
而getClassLoaders
方法则规定了使用类加载器查找资源/类的顺序:
ClassLoader[] getClassLoaders(ClassLoader classLoader) {
return new ClassLoader[]{
classLoader,
defaultClassLoader,
Thread.currentThread().getContextClassLoader(),
getClass().getClassLoader(),
systemClassLoader};
}
读取配置文件
SqlSessionFactoryBuilder
类SqlSessionFactoryBuilder
创建SqlSessionFactory
对象,类中所有方法全部为build
方法及其重载。其中最重要的两个方法为:
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
可以看到builder
方法首先创建了XMLConfigBuilder
类的实例,接着使用该实例创建了DefaultSqlSessionFactory
实例。
XMLConfigBuilder
XMLConfigBuilder
类的构造方法都是如下构造方法的变形:
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
super(new Configuration());
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props);
this.parsed = false;
this.environment = environment;
this.parser = parser;
}
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
SqlSessionFactoryBuilder
类调用的构造方法是第二个构造方法,由此可见传入的inputStram
被处啊入到了XPathParser
对象中,而XMLConfigBuilder
类继承了BaseBuilder
类。BaseBuilder
类是抽象类,有三个属性:Configuration
类对象configuration
,TypeAliasRegistry
类对象typeAliasRegistry
,TypeHandlerRegistry
类对象typeHandlerRegistry
。其中configuration
对象为默认构造方法创建,而typeAliasRegistry
对象和typeHandlerRegistry
对象泽分别由configuration
对象的getTypeAliasRegistry()
方法和getTypeHandlerRegistry()
方法创建。
XPathParser
根据调用关系,XPathParser
对象的构造方法的执行顺序为:
public XPathParser(InputStream inputStream) {
commonConstructor(false, null, null);
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();
}
private Document createDocument(InputSource inputSource) {
// important: this must only be called AFTER common constructor
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
factory.setValidating(validation);
factory.setNamespaceAware(false);
factory.setIgnoringComments(true);
factory.setIgnoringElementContentWhitespace(false);
factory.setCoalescing(false);
factory.setExpandEntityReferences(true);
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setEntityResolver(entityResolver);
builder.setErrorHandler(new ErrorHandler() {
@Override
public void error(SAXParseException exception) throws SAXException {
throw exception;
}
@Override
public void fatalError(SAXParseException exception) throws SAXException {
throw exception;
}
@Override
public void warning(SAXParseException exception) throws SAXException {
// NOP
}
});
return builder.parse(inputSource);
} catch (Exception e) {
throw new BuilderException("Error creating document instance. Cause: " + e, e);
}
}
可以看到在XPathParser
的构造函数中就对配置进行了读取,对配置读取时使用的是DocumentBuilder
创建Document
对象。对XML
文件读取完毕之后,XPathParser
通过parseConfiguration
方法读取配置文件中的配置。parseConfiguration
方法以及其调用的方法将配置文件中的内容通过调用Configuration
中的相应方法保存到Configuration
对象中。
TypeAliasRegistry
TypeAliasRegistry
类的主要功能是注册和查询别名。在TypeAliasRegistry.java
中,TypeAliasRegistry
类的属性有typeAliases
这一HashMap
对象,而TypeAliasRegistry
类中的主要方法resolveAlias
,registerAlias
和getTypeAliases
的行为则是对typeAliases
进行操作。
private final Map<String, Class<?>> typeAliases = new HashMap<>();
typeAliases
主要提供字符串和类的映射。方法registerAlias
将一个名称和一个类相关联起来,getTypeAlias
主要从HashMap
中获取根据名称获取对应类的Class
对象,而resolveAlias
方法的源代码如下:
public <T> Class<T> resolveAlias(String string) {
try {
if (string == null) {
return null;
}
// issue #748
String key = string.toLowerCase(Locale.ENGLISH);
Class<T> value;
if (typeAliases.containsKey(key)) {
value = (Class<T>) typeAliases.get(key);
} else {
value = (Class<T>) Resources.classForName(string);
}
return value;
} catch (ClassNotFoundException e) {
throw new TypeException("Could not resolve type alias '" + string + "'. Cause: " + e, e);
}
}
可以看到, resolveAlias
方法对传入的字符串参数string
,首先将其转换成全部小写,接着如果之前没有建立由改string
到某一类的映射,则使用Resources.classForName
方法获取string
代表的类的Class
对象并建立映射关系。例如,如果有一类名为org.glassyyang.User
,则该方法获取org.glassyyang.User
类对应的Class
对象,接着建立org.glassyyang.user
与Class
对象的映射关系。
分析registryAlias
源码:
public void registerAliases(String packageName) {
registerAliases(packageName, Object.class);
}
public void registerAliases(String packageName, Class<?> superType) {
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
Set<Class<? extends Class<?>>> typeSet = resolverUtil.getClasses();
for (Class<?> type : typeSet) {
// Ignore inner classes and interfaces (including package-info.java)
// Skip also inner classes. See issue #6
if (!type.isAnonymousClass() && !type.isInterface() && !type.isMemberClass()) {
registerAlias(type);
}
}
}
public void registerAlias(Class<?> type) {
String alias = type.getSimpleName();
Alias aliasAnnotation = type.getAnnotation(Alias.class);
if (aliasAnnotation != null) {
alias = aliasAnnotation.value();
}
registerAlias(alias, type);
}
可以看到方法在建立映射关系时,首先会将字符串转换成小写,这也是Mybatis
的别名不区分大小写的原因。
在TypeAliasRegistry
的构造函数中,对Java
中常见的基本类型,包装类型以及对应的数组类型都建立了映射关系;对Date
,BigDecimal
,BigInteger
,Object
以及对应数组对象也建立了映射关系,同时对Map
,HashMap
,List
,ArrayList
,Collection
,Iterator
和ResultSet
对象建立了映射关系。同时在Configuration
对象的构造函数中创建了如下的对应关系:
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);
}
TypeHandlerRegistry
TypeHandlerRegistry
类的主要功能是提供Java
类型与对应的Jdbc
类型之间进行转换的处理句柄。
其中的属性jdbcTypeHandlerMap
提供JdbcType
与相应的处理句柄之间的映射关系,而属性typeHandlerMap
是一个ConcurrentMap
,提供java
类型与Jdbc
类型之间转换的处理句柄TypeHandler
。
TypeHandlerRegistry
对象的属性如下:
// EnumMap,存储JdbcType枚举与TypeHandler<?>之间的映射关系,即保存了JdbcType的处理句柄
private final Map<JdbcType, TypeHandler<?>> jdbcTypeHandlerMap = new EnumMap<>(JdbcType.class);
// ConcurrentHashMap对象,存储Type类与Map<JdbcTYpe, TYpeHandler<?>>之间的映射关系
private final Map<Type, Map<JdbcType, TypeHandler<?>>> typeHandlerMap = new ConcurrentHashMap<>();
// 特殊的TypeHandler,专门处理未知类型
private final TypeHandler<Object> unknownTypeHandler;
//定义类Class对象与TypeHandler之间的映射关系
private final Map<Class<?>, TypeHandler<?>> allTypeHandlersMap = new HashMap<>();
// 定义一个空的Map作为null值的Map
private static final Map<JdbcType, TypeHandler<?>> NULL_TYPE_HANDLER_MAP = Collections.emptyMap();
// 暂时不知道是用来干嘛的
private Class<? extends TypeHandler> defaultEnumTypeHandler = EnumTypeHandler.class;
TypeHandlerRegistry
类的构造函数中注册了基本Java
类型和JDBC
类型相应的处理句柄。其中registry
方法用于注册句柄,提供注册JdbcType
对应处理句柄和Java
类型转换为JdbcType
类型的护理句柄。Mybatis
中默认实现了一些jdbc
类型和java
类型之间转换的处理句柄,有BooleanTypeHandler
,ByteTypeHandler
,ShortTypeHandler
等。这些Handler
提供了jdbc
类型和java
类型的互相转换。
回到BaseBuilder
。可以看到XMLConfigBuilder
继承了BaseBuilder
,并在其基础上新增了parsed
,parser
,environment
和localReflectorFactory
四个属性:
// 是否已解析,防止配置文件被解析多次;
private boolean parsed;
// XML 文件DOM解析包装类,用于解析XML文件
private final XPathParser parser;
//字符串类型,暂时不知道有神码用处
private String environment;
// 反射工厂类,不知道是干什么的
private final ReflectorFactory localReflectorFactory = new DefaultReflectorFactory();
标签:typeAliasRegistry,registerAlias,配置管理,private,public,Mybatis,new,class 来源: https://blog.csdn.net/qq_37718687/article/details/115553685
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。