MyBatis原理(1)-启动流程1

[b]概述:本文按三个部分依次循序渐进对mybatis源码-原理进行分析
[/b]1.MyBatis 启动流程
2.MyBatis 执行流程
3.MyBatis 核心组件

[b]第一部分 启动流程
[/b]

String resource = "mybatis.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

SqlSession openSession = sqlSessionFactory.openSession();
Dept dept = openSession.selectOne("dao.DeptDAO.select",1);
System.out.println(dept.toString());


1. Resources 工具类

public class Resources {

private static ClassLoaderWrapper classLoaderWrapper = new ClassLoaderWrapper();

Resources 通过对ClassLoaderWrapper进一步封装,使调用方无需关心到底调用的是那个类加载器来加载资源文件,为此提供了多个重载的获取资源的方法,分为如下5 类:
1)getResourceURL 从classpath读取文件,返回为URL
2)getResourceAsStream 从classpath读取返回为输入流
3)getResourceAsProperties 同上,返回为properties
4)getResourceAsReader 返回为Reader
5)getResourceAsFile 返回为File
每个方法都有相应的重载方法可提供外部的ClassLoader来加载资源,再看下ClassLoaderWrapper:

public class ClassLoaderWrapper {

ClassLoader defaultClassLoader;
ClassLoader systemClassLoader;

ClassLoaderWrapper() {
try {
//当前系统AppClassLoader,负责加载classpath,是所有应用classloader的父亲
systemClassLoader = ClassLoader.getSystemClassLoader();
} catch (SecurityException ignored) {
// AccessControlException on Google App Engine
}
}

/*
* Get a resource as a URL using the current class path
*
* @param resource - the resource to locate
* @return the resource or null
*/
public URL getResourceAsURL(String resource) {
return getResourceAsURL(resource, getClassLoaders(null));
}

/*
* Get a resource from the classpath, starting with a specific class loader
*
* @param resource - the resource to find
* @param classLoader - the first classloader to try
* @return the stream or null
*/
public URL getResourceAsURL(String resource, ClassLoader classLoader) {
return getResourceAsURL(resource, getClassLoaders(classLoader));
}

/*
* Get a resource from the classpath
*
* @param resource - the resource to find
* @return the stream or null
*/
public InputStream getResourceAsStream(String resource) {
return getResourceAsStream(resource, getClassLoaders(null));
}

/*
* Get a resource from the classpath, starting with a specific class loader
*
* @param resource - the resource to find
* @param classLoader - the first class loader to try
* @return the stream or null
*/
public InputStream getResourceAsStream(String resource, ClassLoader classLoader) {
return getResourceAsStream(resource, getClassLoaders(classLoader));
}

/*
* Find a class on the classpath (or die trying)
*
* @param name - the class to look for
* @return - the class
* @throws ClassNotFoundException Duh.
*/
public Class<?> classForName(String name) throws ClassNotFoundException {
return classForName(name, getClassLoaders(null));
}

/*
* Find a class on the classpath, starting with a specific classloader (or die trying)
*
* @param name - the class to look for
* @param classLoader - the first classloader to try
* @return - the class
* @throws ClassNotFoundException Duh.
*/
public Class<?> classForName(String name, ClassLoader classLoader) throws ClassNotFoundException {
return classForName(name, getClassLoaders(classLoader));
}

/*
* Try to get a resource from a group of classloaders
*
* @param resource - the resource to get
* @param classLoader - the classloaders to examine
* @return the resource or null
*/
InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
for (ClassLoader cl : classLoader) {
if (null != cl) {

// try to find the resource as passed
InputStream returnValue = cl.getResourceAsStream(resource);

// now, some class loaders want this leading "/", so we'll add it and try again if we didn't find the resource
if (null == returnValue) {
returnValue = cl.getResourceAsStream("/" + resource);
}

if (null != returnValue) {
return returnValue;
}
}
}
return null;
}

/*
* Get a resource as a URL using the current class path
*
* @param resource - the resource to locate
* @param classLoader - the class loaders to examine
* @return the resource or null
*/
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;

}

/*
* Attempt to load a class from a group of classloaders
*
* @param name - the class to load
* @param classLoader - the group of classloaders to examine
* @return the class
* @throws ClassNotFoundException - Remember the wisdom of Judge Smails: Well, the world needs ditch diggers, too.
*/
Class<?> classForName(String name, ClassLoader[] classLoader) throws ClassNotFoundException {

for (ClassLoader cl : classLoader) {

if (null != cl) {

try {

Class<?> c = Class.forName(name, true, cl);

if (null != c) {
return c;
}

} catch (ClassNotFoundException e) {
// we'll ignore this until all classloaders fail to locate the class
}

}

}

throw new ClassNotFoundException("Cannot find class: " + name);

}
//如果传入了外部classLoader则getResourceAsStream的时候调用默认使用,传入的第一个
//defaultClassLoader 在此类中未定义
//Thread.currentThread().getContextClassLoader() 创建当前线程的类加载器
// getClass().getClassLoader()加载当前类定义的类加载器默认是AppClassLoader 即ClassLoader.getSystemClassLoader
//systemClassLoader
ClassLoader[] getClassLoaders(ClassLoader classLoader) {
return new ClassLoader[]{
classLoader,
defaultClassLoader,
Thread.currentThread().getContextClassLoader(),
getClass().getClassLoader(),
systemClassLoader};
}

}


后面这三个类加载器在默认情况下都是同一个AppClassLoader的同一个实例,如图:
[img]http://dl.iteye.com/upload/picture/pic/138339/4c6df677-2038-3b3d-9dae-88f0ebba0594.png[/img]
这样做的好处就是拓展性,即便我们提供的mybatis.xml文件在外部,假设自定义了一个URL的ClassLoader,对后面加载其他的mapper.xml也不会有任何影响。
2.SessionFactoryBuilder
SessionFactoryBuilder中全是各式各样的Build方法
public class SqlSessionFactoryBuilder {

public SqlSessionFactory build(Reader reader) {
return build(reader, null, null);
}

public SqlSessionFactory build(Reader reader, String environment) {
return build(reader, environment, null);
}

public SqlSessionFactory build(Reader reader, Properties properties) {
return build(reader, null, properties);
}

public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}

public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}

public SqlSessionFactory build(InputStream inputStream, String environment) {
return build(inputStream, environment, null);
}

public SqlSessionFactory build(InputStream inputStream, Properties properties) {
return build(inputStream, null, properties);
}

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);
}

最主要的还是最后两个构造方法,直接进入XMLConfigBuilder
3.XMLConfigBuilder构造方法
3.1 初始化
 public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}

3.2 XMLMapperEntityResolver初始化
public class XMLMapperEntityResolver implements EntityResolver {

private static final String IBATIS_CONFIG_SYSTEM = "ibatis-3-config.dtd";
private static final String IBATIS_MAPPER_SYSTEM = "ibatis-3-mapper.dtd";
private static final String MYBATIS_CONFIG_SYSTEM = "mybatis-3-config.dtd";
private static final String MYBATIS_MAPPER_SYSTEM = "mybatis-3-mapper.dtd";

private static final String MYBATIS_CONFIG_DTD = "org/apache/ibatis/builder/xml/mybatis-3-config.dtd";
private static final String MYBATIS_MAPPER_DTD = "org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd";

/*
* Converts a public DTD into a local one
*
* @param publicId The public id that is what comes after "PUBLIC"
* @param systemId The system id that is what comes after the public id.
* @return The InputSource for the DTD
*
* @throws org.xml.sax.SAXException If anything goes wrong
*/
@Override
public InputSource resolveEntity(String publicId, String systemId) throws SAXException {
try {
if (systemId != null) {
String lowerCaseSystemId = systemId.toLowerCase(Locale.ENGLISH);
if (lowerCaseSystemId.contains(MYBATIS_CONFIG_SYSTEM) || lowerCaseSystemId.contains(IBATIS_CONFIG_SYSTEM)) {
return getInputSource(MYBATIS_CONFIG_DTD, publicId, systemId);
} else if (lowerCaseSystemId.contains(MYBATIS_MAPPER_SYSTEM) || lowerCaseSystemId.contains(IBATIS_MAPPER_SYSTEM)) {
return getInputSource(MYBATIS_MAPPER_DTD, publicId, systemId);
}
}
return null;
} catch (Exception e) {
throw new SAXException(e.toString());
}
}

private InputSource getInputSource(String path, String publicId, String systemId) {
InputSource source = null;
if (path != null) {
try {
InputStream in = Resources.getResourceAsStream(path);
source = new InputSource(in);
source.setPublicId(publicId);
source.setSystemId(systemId);
} catch (IOException e) {
// ignore, null is ok
}
}
return source;
}

}


3. XPathParser 初始化
public class XPathParser {

private final Document document;
private boolean validation;
private EntityResolver entityResolver;
private Properties variables;
private XPath xpath;

public XPathParser(String xml) {
commonConstructor(false, null, null);
this.document = createDocument(new InputSource(new StringReader(xml)));
}

public XPathParser(Reader reader) {
commonConstructor(false, null, null);
this.document = createDocument(new InputSource(reader));
}

public XPathParser(InputStream inputStream) {
commonConstructor(false, null, null);
this.document = createDocument(new InputSource(inputStream));
}

public XPathParser(Document document) {
commonConstructor(false, null, null);
this.document = document;
}

public XPathParser(String xml, boolean validation) {
commonConstructor(validation, null, null);
this.document = createDocument(new InputSource(new StringReader(xml)));
}

public XPathParser(Reader reader, boolean validation) {
commonConstructor(validation, null, null);
this.document = createDocument(new InputSource(reader));
}

public XPathParser(InputStream inputStream, boolean validation) {
commonConstructor(validation, null, null);
this.document = createDocument(new InputSource(inputStream));
}

public XPathParser(Document document, boolean validation) {
commonConstructor(validation, null, null);
this.document = document;
}

public XPathParser(String xml, boolean validation, Properties variables) {
commonConstructor(validation, variables, null);
this.document = createDocument(new InputSource(new StringReader(xml)));
}

public XPathParser(Reader reader, boolean validation, Properties variables) {
commonConstructor(validation, variables, null);
this.document = createDocument(new InputSource(reader));
}

public XPathParser(InputStream inputStream, boolean validation, Properties variables) {
commonConstructor(validation, variables, null);
this.document = createDocument(new InputSource(inputStream));
}

public XPathParser(Document document, boolean validation, Properties variables) {
commonConstructor(validation, variables, null);
this.document = document;
}

public XPathParser(String xml, boolean validation, Properties variables, EntityResolver entityResolver) {
commonConstructor(validation, variables, entityResolver);
this.document = createDocument(new InputSource(new StringReader(xml)));
}

public XPathParser(Reader reader, boolean validation, Properties variables, EntityResolver entityResolver) {
commonConstructor(validation, variables, entityResolver);
this.document = createDocument(new InputSource(reader));
}

public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
commonConstructor(validation, variables, entityResolver);
this.document = createDocument(new InputSource(inputStream));
}

public XPathParser(Document document, boolean validation, Properties variables, EntityResolver entityResolver) {
commonConstructor(validation, variables, entityResolver);
this.document = document;
}

public void setVariables(Properties variables) {
this.variables = variables;
}

public String evalString(String expression) {
return evalString(document, expression);
}

public String evalString(Object root, String expression) {
String result = (String) evaluate(expression, root, XPathConstants.STRING);
result = PropertyParser.parse(result, variables);
return result;
}

public Boolean evalBoolean(String expression) {
return evalBoolean(document, expression);
}

public Boolean evalBoolean(Object root, String expression) {
return (Boolean) evaluate(expression, root, XPathConstants.BOOLEAN);
}

public Short evalShort(String expression) {
return evalShort(document, expression);
}

public Short evalShort(Object root, String expression) {
return Short.valueOf(evalString(root, expression));
}

public Integer evalInteger(String expression) {
return evalInteger(document, expression);
}

public Integer evalInteger(Object root, String expression) {
return Integer.valueOf(evalString(root, expression));
}

public Long evalLong(String expression) {
return evalLong(document, expression);
}

public Long evalLong(Object root, String expression) {
return Long.valueOf(evalString(root, expression));
}

public Float evalFloat(String expression) {
return evalFloat(document, expression);
}

public Float evalFloat(Object root, String expression) {
return Float.valueOf(evalString(root, expression));
}

public Double evalDouble(String expression) {
return evalDouble(document, expression);
}

public Double evalDouble(Object root, String expression) {
return (Double) evaluate(expression, root, XPathConstants.NUMBER);
}

public List<XNode> evalNodes(String expression) {
return evalNodes(document, expression);
}

public List<XNode> evalNodes(Object root, String expression) {
List<XNode> xnodes = new ArrayList<XNode>();
NodeList nodes = (NodeList) evaluate(expression, root, XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++) {
xnodes.add(new XNode(this, nodes.item(i), variables));
}
return xnodes;
}

public XNode evalNode(String expression) {
return evalNode(document, expression);
}

public XNode evalNode(Object root, String expression) {
Node node = (Node) evaluate(expression, root, XPathConstants.NODE);
if (node == null) {
return null;
}
return new XNode(this, node, variables);
}

private Object evaluate(String expression, Object root, QName returnType) {
try {
return xpath.evaluate(expression, root, returnType);
} catch (Exception e) {
throw new BuilderException("Error evaluating XPath. Cause: " + e, e);
}
}

private Document createDocument(InputSource inputSource) {
// important: this must only be called AFTER common constructor
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
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 {
}
});
return builder.parse(inputSource);
} catch (Exception e) {
throw new BuilderException("Error creating document instance. Cause: " + e, e);
}
}

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();
}

}

这个过程中会调用 commonConstructor进行 xpath和entityResolver的初始化,然后调用CreateDocument对document进行初始化,后面使用Document结合Xpath对xml进行解析。xpath是xml文档查询语言,EntityResolver 实现了EntityResolver 接口,此接口只有一个方法
 public abstract InputSource resolveEntity (String publicId,
String systemId)
throws SAXException, IOException;

解析器在进行解析时会调用此接口进行xml的实现类进行dtd验证XMLMapperEntityResolver
将dtd文件指向jar包中的mapper.xml 和mybatis.config对应的dtd文件。
到此XmlPaser就创建完毕了,这里就是mybatis解析xml的方式DOM+Xpath。

4. 回到XMLConfigBuilder的构造方法
 public XMLConfigBuilder(Reader reader, String environment, Properties props) {
this(new XPathParser(reader, true, props, new XMLMapperEntityResolver()), environment, props);
}
执行完后,继续调用
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;
}

5.Configuration
Configuration 是Mybatis中的核心配置类,包含了mybatis所有的配置信息
继续进行初始化

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);
}

Configuration中包含一个
  protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
属性,其中


public class TypeAliasRegistry {

private final Map<String, Class<?>> TYPE_ALIASES = new HashMap<String, Class<?>>();

public TypeAliasRegistry() {
registerAlias("string", String.class);

registerAlias("byte", Byte.class);
registerAlias("long", Long.class);
registerAlias("short", Short.class);
registerAlias("int", Integer.class);
registerAlias("integer", Integer.class);
registerAlias("double", Double.class);
registerAlias("float", Float.class);
registerAlias("boolean", Boolean.class);

registerAlias("byte[]", Byte[].class);
registerAlias("long[]", Long[].class);
registerAlias("short[]", Short[].class);
registerAlias("int[]", Integer[].class);
registerAlias("integer[]", Integer[].class);
registerAlias("double[]", Double[].class);
registerAlias("float[]", Float[].class);
registerAlias("boolean[]", Boolean[].class);

registerAlias("_byte", byte.class);
registerAlias("_long", long.class);
registerAlias("_short", short.class);
registerAlias("_int", int.class);
registerAlias("_integer", int.class);
registerAlias("_double", double.class);
registerAlias("_float", float.class);
registerAlias("_boolean", boolean.class);

registerAlias("_byte[]", byte[].class);
registerAlias("_long[]", long[].class);
registerAlias("_short[]", short[].class);
registerAlias("_int[]", int[].class);
registerAlias("_integer[]", int[].class);
registerAlias("_double[]", double[].class);
registerAlias("_float[]", float[].class);
registerAlias("_boolean[]", boolean[].class);

registerAlias("date", Date.class);
registerAlias("decimal", BigDecimal.class);
registerAlias("bigdecimal", BigDecimal.class);
registerAlias("biginteger", BigInteger.class);
registerAlias("object", Object.class);

registerAlias("date[]", Date[].class);
registerAlias("decimal[]", BigDecimal[].class);
registerAlias("bigdecimal[]", BigDecimal[].class);
registerAlias("biginteger[]", BigInteger[].class);
registerAlias("object[]", Object[].class);

registerAlias("map", Map.class);
registerAlias("hashmap", HashMap.class);
registerAlias("list", List.class);
registerAlias("arraylist", ArrayList.class);
registerAlias("collection", Collection.class);
registerAlias("iterator", Iterator.class);

registerAlias("ResultSet", ResultSet.class);
}

@SuppressWarnings("unchecked")
// throws class cast exception as well if types cannot be assigned
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 (TYPE_ALIASES.containsKey(key)) {
value = (Class<T>) TYPE_ALIASES.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);
}
}

public void registerAliases(String packageName){
registerAliases(packageName, Object.class);
}

public void registerAliases(String packageName, Class<?> superType){
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
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);
}

public void registerAlias(String alias, Class<?> value) {
if (alias == null) {
throw new TypeException("The parameter alias cannot be null");
}
// issue #748
String key = alias.toLowerCase(Locale.ENGLISH);
if (TYPE_ALIASES.containsKey(key) && TYPE_ALIASES.get(key) != null && !TYPE_ALIASES.get(key).equals(value)) {
throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + TYPE_ALIASES.get(key).getName() + "'.");
}
TYPE_ALIASES.put(key, value);
}

public void registerAlias(String alias, String value) {
try {
registerAlias(alias, Resources.classForName(value));
} catch (ClassNotFoundException e) {
throw new TypeException("Error registering type alias "+alias+" for "+value+". Cause: " + e, e);
}
}

/**
* @since 3.2.2
*/
public Map<String, Class<?>> getTypeAliases() {
return Collections.unmodifiableMap(TYPE_ALIASES);
}

}

默认注册了所有的基本类型、包装类型、集合类型等简写到class的映射。
在构造函数初始化之前还会对默认变量进行赋值,下面对Configuration中几个重要的变量进行初始化
反射工具包ReflectorFactory

public class DefaultReflectorFactory implements ReflectorFactory {
private boolean classCacheEnabled = true;
private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<Class<?>, Reflector>();

public DefaultReflectorFactory() {
}

@Override
public boolean isClassCacheEnabled() {
return classCacheEnabled;
}

@Override
public void setClassCacheEnabled(boolean classCacheEnabled) {
this.classCacheEnabled = classCacheEnabled;
}

@Override
public Reflector findForClass(Class<?> type) {
if (classCacheEnabled) {
// synchronized (type) removed see issue #461
Reflector cached = reflectorMap.get(type);
if (cached == null) {
cached = new Reflector(type);
reflectorMap.put(type, cached);
}
return cached;
} else {
return new Reflector(type);
}
}

}

public interface ReflectorFactory {

boolean isClassCacheEnabled();

void setClassCacheEnabled(boolean classCacheEnabled);

Reflector findForClass(Class<?> type);
}

public class Reflector {

private final Class<?> type;
private final String[] readablePropertyNames;
private final String[] writeablePropertyNames;
private final Map<String, Invoker> setMethods = new HashMap<String, Invoker>();
private final Map<String, Invoker> getMethods = new HashMap<String, Invoker>();
private final Map<String, Class<?>> setTypes = new HashMap<String, Class<?>>();
private final Map<String, Class<?>> getTypes = new HashMap<String, Class<?>>();
private Constructor<?> defaultConstructor;

private Map<String, String> caseInsensitivePropertyMap = new HashMap<String, String>();

public Reflector(Class<?> clazz) {
type = clazz;
addDefaultConstructor(clazz);
addGetMethods(clazz);
addSetMethods(clazz);
addFields(clazz);
readablePropertyNames = getMethods.keySet().toArray(new String[getMethods.keySet().size()]);
writeablePropertyNames = setMethods.keySet().toArray(new String[setMethods.keySet().size()]);
for (String propName : readablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
for (String propName : writeablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
}
//
private void addDefaultConstructor(Class<?> clazz) {
Constructor<?>[] consts = clazz.getDeclaredConstructors();
for (Constructor<?> constructor : consts) {
if (constructor.getParameterTypes().length == 0) {
//检查是否能访问私有方法、属性
if (canAccessPrivateMethods()) {
try {
constructor.setAccessible(true);
} catch (Exception e) {
// Ignored. This is only a final precaution, nothing we can do.
}
}
//检查constructor 是否设置上能访问,否则defaultConstructor =null
if (constructor.isAccessible()) {
this.defaultConstructor = constructor;
}
}
}
}

private void addGetMethods(Class<?> cls) {
Map<String, List<Method>> conflictingGetters = new HashMap<String, List<Method>>();
Method[] methods = getClassMethods(cls);
for (Method method : methods) {
if (method.getParameterTypes().length > 0) {
continue;
}
String name = method.getName();
if ((name.startsWith("get") && name.length() > 3)
|| (name.startsWith("is") && name.length() > 2)) {
name = PropertyNamer.methodToProperty(name);
//
addMethodConflict(conflictingGetters, name, method);
}
}
resolveGetterConflicts(conflictingGetters);
}

private void resolveGetterConflicts(Map<String, List<Method>> conflictingGetters) {
//list中最多只能有 一个isB 一个getB ,分为返回值相同 返回值不同,返回值不同分为类型
//不同,和超类子类的返回值不同,所以getB有bool,返回类型A,返回类型B,isB也是三
//种,其中B和A有父子关系,一共有9种可能
for (Entry<String, List<Method>> entry : conflictingGetters.entrySet()) {
Method winner = null;
String propName = entry.getKey();
for (Method candidate : entry.getValue()) {
if (winner == null) {
winner = candidate;
continue;
}

Class<?> winnerType = winner.getReturnType();

Class<?> candidateType = candidate.getReturnType();

if (candidateType.equals(winnerType)) {// 返回类型相等只有 A,B和bool三种情况
//两个类型相等 后者如果不是bool ,无论谁在前面都抛出异常说明is和get返回相同值
if (!boolean.class.equals(candidateType)) {
throw new ReflectionException(
"Illegal overloaded getter method with ambiguous type for property "
+ propName + " in class " + winner.getDeclaringClass()
+ ". This breaks the JavaBeans specification and can cause unpredictable results.");
//返回类型相同,并且同时是bool但是后面这个是以is开头,交换
} else if (candidate.getName().startsWith("is")) {
winner = candidate;
}
//返回值不同,且前者是后者的子类-->winner保持当前值
} else if (candidateType.isAssignableFrom(winnerType)) {
// OK getter type is descendant
//返回值不同,且前者是后者的父类->交换调整返回子类
} else if (winnerType.isAssignableFrom(candidateType)) {
winner = candidate;
} else {
//抛出异常两个返回类型直接没有任何关联并且其中一个是boolean类型
throw new ReflectionException(
"Illegal overloaded getter method with ambiguous type for property "
+ propName + " in class " + winner.getDeclaringClass()
+ ". This breaks the JavaBeans specification and can cause unpredictable results.");
}
}
addGetMethod(propName, winner);
}
}

private void addGetMethod(String name, Method method) {
if (isValidPropertyName(name)) {
getMethods.put(name, new MethodInvoker(method));
Type returnType = TypeParameterResolver.resolveReturnType(method, type);
getTypes.put(name, typeToClass(returnType));
}
}

private void addSetMethods(Class<?> cls) {
Map<String, List<Method>> conflictingSetters = new HashMap<String, List<Method>>();
Method[] methods = getClassMethods(cls);
for (Method method : methods) {
String name = method.getName();
if (name.startsWith("set") && name.length() > 3) {
if (method.getParameterTypes().length == 1) {
name = PropertyNamer.methodToProperty(name);
addMethodConflict(conflictingSetters, name, method);
}
}
}
resolveSetterConflicts(conflictingSetters);
}

private void addMethodConflict(Map<String, List<Method>> conflictingMethods, String name, Method method) {
List<Method> list = conflictingMethods.get(name);
if (list == null) {
list = new ArrayList<Method>();
conflictingMethods.put(name, list);
}
list.add(method);
}

private void resolveSetterConflicts(Map<String, List<Method>> conflictingSetters) {
for (String propName : conflictingSetters.keySet()) {
List<Method> setters = conflictingSetters.get(propName);
Class<?> getterType = getTypes.get(propName);
Method match = null;
ReflectionException exception = null;
for (Method setter : setters) {
Class<?> paramType = setter.getParameterTypes()[0];
if (paramType.equals(getterType)) {
// should be the best match
match = setter;
break;
}
if (exception == null) {
try {
match = pickBetterSetter(match, setter, propName);
} catch (ReflectionException e) {
// there could still be the 'best match'
match = null;
exception = e;
}
}
}
if (match == null) {
throw exception;
} else {
addSetMethod(propName, match);
}
}
}

private Method pickBetterSetter(Method setter1, Method setter2, String property) {
if (setter1 == null) {
return setter2;
}
Class<?> paramType1 = setter1.getParameterTypes()[0];
Class<?> paramType2 = setter2.getParameterTypes()[0];
if (paramType1.isAssignableFrom(paramType2)) {
return setter2;
} else if (paramType2.isAssignableFrom(paramType1)) {
return setter1;
}
throw new ReflectionException("Ambiguous setters defined for property '" + property + "' in class '"
+ setter2.getDeclaringClass() + "' with types '" + paramType1.getName() + "' and '"
+ paramType2.getName() + "'.");
}

private void addSetMethod(String name, Method method) {
if (isValidPropertyName(name)) {
setMethods.put(name, new MethodInvoker(method));
Type[] paramTypes = TypeParameterResolver.resolveParamTypes(method, type);
setTypes.put(name, typeToClass(paramTypes[0]));
}
}

private Class<?> typeToClass(Type src) {
Class<?> result = null;
if (src instanceof Class) {
result = (Class<?>) src;
} else if (src instanceof ParameterizedType) {
result = (Class<?>) ((ParameterizedType) src).getRawType();
} else if (src instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) src).getGenericComponentType();
if (componentType instanceof Class) {
result = Array.newInstance((Class<?>) componentType, 0).getClass();
} else {
Class<?> componentClass = typeToClass(componentType);
result = Array.newInstance((Class<?>) componentClass, 0).getClass();
}
}
if (result == null) {
result = Object.class;
}
return result;
}

private void addFields(Class<?> clazz) {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (canAccessPrivateMethods()) {
try {
field.setAccessible(true);
} catch (Exception e) {
// Ignored. This is only a final precaution, nothing we can do.
}
}
if (field.isAccessible()) {
if (!setMethods.containsKey(field.getName())) {
// issue #379 - removed the check for final because JDK 1.5 allows
// modification of final fields through reflection (JSR-133). (JGB)
// pr #16 - final static can only be set by the classloader
int modifiers = field.getModifiers();
if (!(Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers))) {
addSetField(field);
}
}
if (!getMethods.containsKey(field.getName())) {
addGetField(field);
}
}
}
if (clazz.getSuperclass() != null) {
addFields(clazz.getSuperclass());
}
}

private void addSetField(Field field) {
if (isValidPropertyName(field.getName())) {
setMethods.put(field.getName(), new SetFieldInvoker(field));
Type fieldType = TypeParameterResolver.resolveFieldType(field, type);
setTypes.put(field.getName(), typeToClass(fieldType));
}
}

private void addGetField(Field field) {
if (isValidPropertyName(field.getName())) {
getMethods.put(field.getName(), new GetFieldInvoker(field));
Type fieldType = TypeParameterResolver.resolveFieldType(field, type);
getTypes.put(field.getName(), typeToClass(fieldType));
}
}

private boolean isValidPropertyName(String name) {
return !(name.startsWith("$") || "serialVersionUID".equals(name) || "class".equals(name));
}

/*
* This method returns an array containing all methods
* declared in this class and any superclass.
* We use this method, instead of the simpler Class.getMethods(),
* because we want to look for private methods as well.
*
* @param cls The class
* @return An array containing all methods in this class
*/
//返回当前类、超类所有方法包括私有方法
private Method[] getClassMethods(Class<?> cls) {
Map<String, Method> uniqueMethods = new HashMap<String, Method>();
Class<?> currentClass = cls;
while (currentClass != null && currentClass != Object.class) {//循环直到Object
addUniqueMethods(uniqueMethods, currentClass.getDeclaredMethods());

// we also need to look for interface methods -
// because the class may be abstract
Class<?>[] interfaces = currentClass.getInterfaces();
for (Class<?> anInterface : interfaces) {
addUniqueMethods(uniqueMethods, anInterface.getMethods());
}

currentClass = currentClass.getSuperclass();
}

Collection<Method> methods = uniqueMethods.values();

return methods.toArray(new Method[methods.size()]);
}

private void addUniqueMethods(Map<String, Method> uniqueMethods, Method[] methods) {
for (Method currentMethod : methods) {
//Bridge方法是 1.5引入泛型后,class字节码为了兼容自动生成的方法
if (!currentMethod.isBridge()) {
// //returnType#methodName:parameter1,parameter2...
String signature = getSignature(currentMethod);
// check to see if the method is already known
// if it is known, then an extended class must have
// overridden a method
if (!uniqueMethods.containsKey(signature)) {
if (canAccessPrivateMethods()) {
try {
currentMethod.setAccessible(true);
} catch (Exception e) {
// Ignored. This is only a final precaution, nothing we can do.
}
}

uniqueMethods.put(signature, currentMethod);
}
}
}
}
//returnType#methodName:parameter1,parameter2...
private String getSignature(Method method) {
StringBuilder sb = new StringBuilder();
Class<?> returnType = method.getReturnType();
if (returnType != null) {
sb.append(returnType.getName()).append('#');
}
sb.append(method.getName());
Class<?>[] parameters = method.getParameterTypes();
for (int i = 0; i < parameters.length; i++) {
if (i == 0) {
sb.append(':');
} else {
sb.append(',');
}
sb.append(parameters[i].getName());
}
return sb.toString();
}

private static boolean canAccessPrivateMethods() {
try {
SecurityManager securityManager = System.getSecurityManager();
if (null != securityManager) {
securityManager.checkPermission(new ReflectPermission("suppressAccessChecks"));
}
} catch (SecurityException e) {
return false;
}
return true;
}

/*
* Gets the name of the class the instance provides information for
*
* @return The class name
*/
public Class<?> getType() {
return type;
}

public Constructor<?> getDefaultConstructor() {
if (defaultConstructor != null) {
return defaultConstructor;
} else {
throw new ReflectionException("There is no default constructor for " + type);
}
}

public boolean hasDefaultConstructor() {
return defaultConstructor != null;
}

public Invoker getSetInvoker(String propertyName) {
Invoker method = setMethods.get(propertyName);
if (method == null) {
throw new ReflectionException("There is no setter for property named '" + propertyName + "' in '" + type + "'");
}
return method;
}

public Invoker getGetInvoker(String propertyName) {
Invoker method = getMethods.get(propertyName);
if (method == null) {
throw new ReflectionException("There is no getter for property named '" + propertyName + "' in '" + type + "'");
}
return method;
}

/*
* Gets the type for a property setter
*
* @param propertyName - the name of the property
* @return The Class of the propery setter
*/
public Class<?> getSetterType(String propertyName) {
Class<?> clazz = setTypes.get(propertyName);
if (clazz == null) {
throw new ReflectionException("There is no setter for property named '" + propertyName + "' in '" + type + "'");
}
return clazz;
}

/*
* Gets the type for a property getter
*
* @param propertyName - the name of the property
* @return The Class of the propery getter
*/
public Class<?> getGetterType(String propertyName) {
Class<?> clazz = getTypes.get(propertyName);
if (clazz == null) {
throw new ReflectionException("There is no getter for property named '" + propertyName + "' in '" + type + "'");
}
return clazz;
}

/*
* Gets an array of the readable properties for an object
*
* @return The array
*/
public String[] getGetablePropertyNames() {
return readablePropertyNames;
}

/*
* Gets an array of the writeable properties for an object
*
* @return The array
*/
public String[] getSetablePropertyNames() {
return writeablePropertyNames;
}

/*
* Check to see if a class has a writeable property by name
*
* @param propertyName - the name of the property to check
* @return True if the object has a writeable property by the name
*/
public boolean hasSetter(String propertyName) {
return setMethods.keySet().contains(propertyName);
}

/*
* Check to see if a class has a readable property by name
*
* @param propertyName - the name of the property to check
* @return True if the object has a readable property by the name
*/
public boolean hasGetter(String propertyName) {
return getMethods.keySet().contains(propertyName);
}

public String findPropertyName(String name) {
return caseInsensitivePropertyMap.get(name.toUpperCase(Locale.ENGLISH));
}
}

工厂设计模式:DefaultReflectorFactory实现了ReflectorFactory接口,按类缓存Reflector,Reflector中包含当前类的所有元数据信息:getter、setter、可读、可写字段 ,以及getter,Setter对应的Invoker,Invoker是对反射的轻量级封装:

public interface Invoker {
Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException;

Class<?> getType();
}

Invoker接口有三个实现类:GetFieldInvoker、MethodInvoker、SetFieldInvoker,其中MethodInvoker:

public class MethodInvoker implements Invoker {

private final Class<?> type;
private final Method method;

public MethodInvoker(Method method) {
this.method = method;

if (method.getParameterTypes().length == 1) {
type = method.getParameterTypes()[0];
} else {
type = method.getReturnType();
}
}

@Override
public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {
return method.invoke(target, args);
}

@Override
public Class<?> getType() {
return type;
}
}

这样做的好处就是:定义接口将设置值与反射隔离,只关注Invoker,而不用管是到底是怎样设置值。
TODO 后面补充TypeParameterResolver
初始化 DefaultObjectFactory

public interface ObjectFactory {

/**
* Sets configuration properties.
* @param properties configuration properties
*/
void setProperties(Properties properties);

/**
* Creates a new object with default constructor.
* @param type Object type
* @return
*/
<T> T create(Class<T> type);

/**
* Creates a new object with the specified constructor and params.
* @param type Object type
* @param constructorArgTypes Constructor argument types
* @param constructorArgs Constructor argument values
* @return
*/
/
<T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);

/**
* Returns true if this object can have a set of other objects.
* It's main purpose is to support non-java.util.Collection objects like Scala collections.
*
* @param type Object type
* @return whether it is a collection or not
* @since 3.1.0
*/
<T> boolean isCollection(Class<T> type);
}

实现类

public class DefaultObjectFactory implements ObjectFactory, Serializable {

private static final long serialVersionUID = -8855120656740914948L;

@Override
public <T> T create(Class<T> type) {
return create(type, null, null);
}

@SuppressWarnings("unchecked")
@Override
public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
//传入指定类型,构造参数类型、构造函数值 创建对象,后面两个参数其中一个为空则表示调用默认构造函数
//检查对象是否是集合对象
Class<?> classToCreate = resolveInterface(type);
// we know types are assignable
return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
}

@Override
public void setProperties(Properties properties) {
// no props for default
//如果要自定义对象工厂,可在config文件中指定property属性
}

private <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
try {
Constructor<T> constructor;
if (constructorArgTypes == null || constructorArgs == null) {
constructor = type.getDeclaredConstructor();
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
return constructor.newInstance();
}
constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[constructorArgTypes.size()]));
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
} catch (Exception e) {
StringBuilder argTypes = new StringBuilder();
if (constructorArgTypes != null && !constructorArgTypes.isEmpty()) {
for (Class<?> argType : constructorArgTypes) {
argTypes.append(argType.getSimpleName());
argTypes.append(",");
}
argTypes.deleteCharAt(argTypes.length() - 1); // remove trailing ,
}
StringBuilder argValues = new StringBuilder();
if (constructorArgs != null && !constructorArgs.isEmpty()) {
for (Object argValue : constructorArgs) {
argValues.append(String.valueOf(argValue));
argValues.append(",");
}
argValues.deleteCharAt(argValues.length() - 1); // remove trailing ,
}
throw new ReflectionException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + e, e);
}
}

protected Class<?> resolveInterface(Class<?> type) {
Class<?> classToCreate;
if (type == List.class || type == Collection.class || type == Iterable.class) {
classToCreate = ArrayList.class;
} else if (type == Map.class) {
classToCreate = HashMap.class;
} else if (type == SortedSet.class) { // issue #510 Collections Support
classToCreate = TreeSet.class;
} else if (type == Set.class) {
classToCreate = HashSet.class;
} else {
classToCreate = type;
}
return classToCreate;
}

@Override
public <T> boolean isCollection(Class<T> type) {
return Collection.class.isAssignableFrom(type);
}


DefaultObjectFactory具有创建普通对象和Collection对象的功能
创建 DefaultObjectWrapperFactory

public interface ObjectWrapperFactory {

boolean hasWrapperFor(Object object);

ObjectWrapper getWrapperFor(MetaObject metaObject, Object object);

}
public class DefaultObjectWrapperFactory implements ObjectWrapperFactory {

@Override
public boolean hasWrapperFor(Object object) {
return false;
}

@Override
public ObjectWrapper getWrapperFor(MetaObject metaObject, Object object) {
throw new ReflectionException("The DefaultObjectWrapperFactory should never be called to provide an ObjectWrapper.");
}


TODO 默认是空的 现在还不清楚这个有什么用
创建ProxyFactory
//TODO
创建 MapperRegistry
//TODO
创建InterceptorChain
//创建 TypeHandlerRegistry
等等
6.初始化父类初始化BaseBuilder
BaseBuilder 两个成员变量typeAliasRegistry和typeHandlerRegistry,可从别名找到类型,再从类型找到类型对应的处理器。
7.继续执行XMLConfigBuilder
初始化私有变量localReflectorFactory,在configuration中也有这样一个reflectorFactory的实例。
8.初始化ErrorContext并设置值
ErrorContext使用ThreadLocal 存储每个线程对应的错误信息

private static final ThreadLocal<ErrorContext> LOCAL = new ThreadLocal<ErrorContext>();

private ErrorContext stored;
private String resource;
private String activity;
private String object;
private String message;
private String sql;
private Throwable cause;

每个错误信息都包含:当前错误文件,当前activity,当前object ,错误消息,sql等,通过reset方法可重置当前线程错误信息上下文,最后通过toString格式化输出。
9. 设置Configuration变量 可覆盖原有配置信息
10.到此XMLConfigBuilder构造方法执行完毕,总结一下这个过程中大致做了哪些工作:
1)XPathParser 解析器的初始化,赋给XMLConfigBuilder的parser
2)初始化Configuration
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Tomcat是一种开源的Servlet容器,它的启动原理是通过读取配置文件、加载相关类和文件,创建并初始化Web应用程序的运行环境,最后启动HTTP服务器监听客户端请求。 Spring是一个开箱即用的Java企业级应用程序开发框架,它的启动原理是通过读取配置文件,加载配置文件中定义的Bean定义和其他相关配置信息,然后根据这些信息创建和管理应用程序的各个组件。Spring容器在启动过程中会初始化相关的Bean实例,并完成依赖注入等操作,最终将这些组件纳入管理范围,供应用程序使用。 SpringMVC是基于Spring框架的MVC(Model-View-Controller)Web应用程序开发框架,它的启动原理也是跟Spring类似。在SpringMVC的启动过程中,首先会读取配置文件,加载配置文件中定义的Controller、View Resolver等组件,并进行相关的初始化操作。然后SpringMVC容器会根据请求的URL路径匹配相应的Controller,执行对应的业务逻辑,最后返回相应的结果。 MyBatis是一种持久层框架,用于简化数据库访问的过程。在MyBatis的启动原理中,先读取配置文件,加载配置的数据库连接信息和SQL映射文件等。然后MyBatis会根据这些配置信息创建数据库连接池,以及初始化SQL语句的映射关系。启动之后,MyBatis会通过数据库连接池建立与数据库的连接,并执行应用程序传递的SQL语句,最后将查询结果返回给应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值