小程序素材网站解析源码分享?微信小程序素材

各位老铁们,大家好,今天由我来为大家分享小程序素材网站解析源码分享,以及微信小程序素材的相关问题知识,希望对大家有所帮助。如果可以帮助到大家,还望关注收藏下本站,您的支持是我们最大的动力,谢谢大家了哈,下面我们开始吧!

本文我们来看看MyBatis的核心流程,养成阅读好习惯,从关注开始!

更多Java相关资料可以关注公众号【Java大蜗牛】发送:6

核心流程分析

??首先来看看MyBatis的主要工作流程图

分析源码我们还是从编程式的Demo入手

/**\n*MyBatisgetMapper方法的使用\n*/\n@Test\npublicvoidtest2()throwsException{\n//1.获取配置文件\nInputStreamin=Resources.getResourceAsStream(&34;);\n//2.加载解析配置文件并获取SqlSessionFactory对象\nSqlSessionFactoryfactory=newSqlSessionFactoryBuilder().build(in);\n//3.根据SqlSessionFactory对象获取SqlSession对象\nSqlSessionsqlSession=factory.openSession();\n//4.通过SqlSession中提供的API方法来操作数据库\nUserMappermapper=sqlSession.getMapper(UserMapper.class);\nList<User>list=mapper.selectUserList();\nfor(Useruser:list){\nSystem.out.println(user);\n}\n//5.关闭会话\nsqlSession.close();\n}

上面我们通过一个比较复杂的步骤实现了MyBatis的数据库查询操作。下面我们会按照这5个步骤来分析MyBatis的运行原理

看源码的注意事项

一定要带着问题去看,猜想验证。不要只记忆流程,学编程风格,设计思想(他的代码为什么这么写?如果不这么写呢?包括接口的定义,类的职责,涉及模式的应用,高级语法等等)。先抓重点,就像开车熟路,哪个地方限速,哪个地方变道,要走很多次。先走主干道,再去、覆盖分支小路。记录核心流程和对象,总结层次、结构、关系,输出(图片或者待注释的源码)。培养看源码的信心和感觉,从带着看到自己去看,看更多的源码。debug还是直接Ctrl+Alt+B跟方法?debug可以看到实际的值,比如到底是哪个实现类,value到底是什么。但是Ctrl+Alt+B不一定能走到真正的对象,比如有代理或者父类方法,或者多个实现的时候。熟悉流程之后,直接跟方法。

1.核心对象的生命周期

1.1SqlSessionFactoryBuiler

首先是SqlSessionFactoryBuiler。它是用来构建SqlSessionFactory的,而SqlSessionFactory只需要一个,所以只要构建了这一个SqlSessionFactory,它的使命就完成了,也就没有存在的意义了。所以它的生命周期只存在于方法的局部。

1.2SqlSessionFactory

SqlSessionFactory是用来创建SqlSession的,每次应用程序访问数据库,都需要创建一个会话。因为我们一直有创建会话的需要,所以SqlSessionFactory应该存在于应用的整个生命周期中(作用域是应用作用域)。创建SqlSession只需要一个实例来做这件事就行了,否则会产生很多的混乱,和浪费资源。所以我们要采用单例模式。

1.3SqlSession

SqlSession是一个会话,因为它不是线程安全的,不能在线程间共享。所以我们在请求开始的时候创建一个SqlSession对象,在请求结束或者说方法执行完毕的时候要及时关闭它(一次请求或者操作中)。

1.4Mapper

?Mapper(实际上是一个代理对象)是从SqlSession中获取的。

UserMappermapper=sqlSession.getMapper(UserMapper.class);

它的作用是发送SQL来操作数据库的数据。它应该在一个SqlSession事务方法之内。

2SqlSessionFactory

?首先我们来看下SqlSessionFactory对象的获取

SqlSessionFactoryfactory=newSqlSessionFactoryBuilder().build(in);

2.1SqlSessionFactoryBuilder

首先我们new了一个SqlSessionFactoryBuilder,这是建造者模式的运用(建造者模式用来创建复杂对象,而不需要关注内部细节,是一种封装的体现)。MyBatis中很多地方用到了建造者模式(名字以Builder结尾的类还有9个)。

SqlSessionFactoryBuilder中用来创建SqlSessionFactory对象的方法是build(),build()方法有9个重载,可以用不同的方式来创建SqlSessionFactory对象。SqlSessionFactory对象默认是单例的。

publicSqlSessionFactorybuild(InputStreaminputStream,Stringenvironment,Propertiesproperties){\ntry{\n//用于解析mybatis-config.xml,同时创建了Configuration对象>>\nXMLConfigBuilderparser=newXMLConfigBuilder(inputStream,environment,properties);\n//解析XML,最终返回一个DefaultSqlSessionFactory>>\nreturnbuild(parser.parse());\n}catch(Exceptione){\nthrowExceptionFactory.wrapException(&34;,e);\n}finally{\nErrorContext.instance().reset();\ntry{\ninputStream.close();\n}catch(IOExceptione){\n//Intentionallyignore.Preferpreviouserror.\n}\n}\n}

在build方法中首先是创建了一个XMLConfigBuilder对象,XMLConfigBuilder是抽象类BaseBuilder的一个子类,专门用来解析全局配置文件,针对不同的构建目标还有其他的一些子类(关联到源码路径),比如:

XMLMapperBuilder:解析Mapper映射器XMLStatementBuilder:解析增删改查标签XMLScriptBuilder:解析动态SQL

然后是执行了

build(parser.parse());

构建的代码,parser.parse()方法返回的是一个Configuration对象,build方法的如下

publicSqlSessionFactorybuild(Configurationconfig){\nreturnnewDefaultSqlSessionFactory(config);\n}

在这儿我们可以看到SessionFactory最终实现是DefaultSqlSessionFactory对象。

2.2XMLConfigBuilder

?然后我们再来看下XMLConfigBuilder初始化的时候做了哪些操作

publicXMLConfigBuilder(InputStreaminputStream,Stringenvironment,Propertiesprops){\n//EntityResolver的实现类是XMLMapperEntityResolver来完成配置文件的校验,根据对应的DTD文件来实现\nthis(newXPathParser(inputStream,true,props,newXMLMapperEntityResolver()),environment,props);\n}

再去进入重载的构造方法中

privateXMLConfigBuilder(XPathParserparser,Stringenvironment,Propertiesprops){\nsuper(newConfiguration());//完成了Configuration的初始化\nErrorContext.instance().resource(&34;);\nthis.configuration.setVariables(props);//设置对应的Properties属性\nthis.parsed=false;//设置是否解析的标志为false\nthis.environment=environment;//初始化environment\nthis.parser=parser;//初始化解析器\n}

2.3Configuration

?然后我们可以看下Configuration初始化做了什么操作

完成了类型别名的注册工作,通过上面的分析我们可以看到XMLConfigBuilder完成了XML文件的解析对应XPathParser和Configuration对象的初始化操作,然后我们再来看下parse方法到底是如何解析配置文件的

2.4parse解析

parser.parse()

进入具体的解析方法

publicConfigurationparse(){\n//检查是否已经解析过了\nif(parsed){\nthrownewBuilderException(&34;);\n}\nparsed=true;\n//XPathParser,dom和SAX都有用到>>开始解析\nparseConfiguration(parser.evalNode(&34;));\nreturnconfiguration;\n}

parseConfiguration方法

privatevoidparseConfiguration(XNoderoot){\ntry{\n//issue34;properties&34;settings&34;typeAliases&34;plugins&34;objectFactory&34;objectWrapperFactory&34;reflectorFactory&631\n//创建了数据源>>\nenvironmentsElement(root.evalNode(&34;));\ndatabaseIdProviderElement(root.evalNode(&34;));\ntypeHandlerElement(root.evalNode(&34;));\n//解析引用的Mapper映射器\nmapperElement(root.evalNode(&34;));\n}catch(Exceptione){\nthrownewBuilderException(&34;+e,e);\n}\n}

2.4.1全局配置文件解析

properties解析

privatevoidpropertiesElement(XNodecontext)throwsException{\nif(context!=null){\n//创建了一个Properties对象,后面可以用到\nPropertiesdefaults=context.getChildrenAsProperties();\nStringresource=context.getStringAttribute(&34;);\nStringurl=context.getStringAttribute(&34;);\nif(resource!=null&&url!=null){\n//url和resource不能同时存在\nthrownewBuilderException(&34;);\n}\n//加载resource或者url属性中指定的properties文件\nif(resource!=null){\ndefaults.putAll(Resources.getResourceAsProperties(resource));\n}elseif(url!=null){\ndefaults.putAll(Resources.getUrlAsProperties(url));\n}\nPropertiesvars=configuration.getVariables();\nif(vars!=null){\n//和Configuration中的variables属性合并\ndefaults.putAll(vars);\n}\n//更新对应的属性信息\nparser.setVariables(defaults);\nconfiguration.setVariables(defaults);\n}\n}

第一个是解析<properties>标签,读取我们引入的外部配置文件,例如db.properties。

这里面又有两种类型,一种是放在resource目录下的,是相对路径,一种是写的绝对路径的(url)。

解析的最终结果就是我们会把所有的配置信息放到名为defaults的Properties对象里面(Hashtable对象,KV存储),最后把XPathParser和Configuration的Properties属性都设置成我们填充后的Properties对象。

settings解析

privatePropertiessettingsAsProperties(XNodecontext){\nif(context==null){\nreturnnewProperties();\n}\n//获取settings节点下的所有的子节点\nPropertiesprops=context.getChildrenAsProperties();\n//Checkthatallsettingsareknowntotheconfigurationclass\nMetaClassmetaConfig=MetaClass.forClass(Configuration.class,localReflectorFactory);\nfor(Objectkey:props.keySet()){\n//\nif(!metaConfig.hasSetter(String.valueOf(key))){\nthrownewBuilderException(&34;+key+&34;);\n}\n}\nreturnprops;\n}

getChildrenAsProperties方法就是具体的解析了

publicPropertiesgetChildrenAsProperties(){\nPropertiesproperties=newProperties();\nfor(XNodechild:getChildren()){\n//获取对应的name和value属性\nStringname=child.getStringAttribute(&34;);\nStringvalue=child.getStringAttribute(&34;);\nif(name!=null&&value!=null){\nproperties.setProperty(name,value);\n}\n}\nreturnproperties;\n}

loadCustomVfs(settings)方法

?loadCustomVfs是获取VitualFileSystem的自定义实现类,比如要读取本地文件,或者FTP远程文件的时候,就可以用到自定义的VFS类。

根据<settings>标签里面的<vfsImpl>标签,生成了一个抽象类VFS的子类,在MyBatis中有JBoss6VFS和DefaultVFS两个实现,在io包中。

privatevoidloadCustomVfs(Propertiesprops)throwsClassNotFoundException{\nStringvalue=props.getProperty(&34;);\nif(value!=null){\nString[]clazzes=value.split(&34;);\nfor(Stringclazz:clazzes){\nif(!clazz.isEmpty()){\n@SuppressWarnings(&34;)\nClass<?extendsVFS>vfsImpl=(Class<?extendsVFS>)Resources.classForName(clazz);\nconfiguration.setVfsImpl(vfsImpl);\n}\n}\n}\n}\n

最后赋值到Configuration中。

loadCustomLogImpl(settings)方法

loadCustomLogImpl是根据<logImpl>标签获取日志的实现类,我们可以用到很多的日志的方案,包括LOG4J,LOG4J2,SLF4J等等,在logging包中。

privatevoidloadCustomLogImpl(Propertiesprops){\nClass<?extendsLog>logImpl=resolveClass(props.getProperty(&34;));\nconfiguration.setLogImpl(logImpl);\n}

typeAliases解析

?这一步是类型别名的解析

privatevoidtypeAliasesElement(XNodeparent){\n//放入TypeAliasRegistry\nif(parent!=null){\nfor(XNodechild:parent.getChildren()){\nif(&34;.equals(child.getName())){\nStringtypeAliasPackage=child.getStringAttribute(&34;);\nconfiguration.getTypeAliasRegistry().registerAliases(typeAliasPackage);\n}else{\nStringalias=child.getStringAttribute(&34;);\nStringtype=child.getStringAttribute(&34;);\ntry{\nClass<?>clazz=Resources.classForName(type);\nif(alias==null){\n//扫描@Alias注解使用\ntypeAliasRegistry.registerAlias(clazz);\n}else{\n//直接注册\ntypeAliasRegistry.registerAlias(alias,clazz);\n}\n}catch(ClassNotFoundExceptione){\nthrownewBuilderException(&39;&34;&34;+e,e);\n}\n}\n}\n}\n}

plugins解析

?插件标签的解析

privatevoidpluginElement(XNodeparent)throwsException{\nif(parent!=null){\nfor(XNodechild:parent.getChildren()){\n//获取<plugin>节点的interceptor属性的值\nStringinterceptor=child.getStringAttribute(&34;);\n//获取<plugin>下的所有的properties子节点\nPropertiesproperties=child.getChildrenAsProperties();\n//获取Interceptor对象\nInterceptorinterceptorInstance=(Interceptor)resolveClass(interceptor).getDeclaredConstructor().newInstance();\n//设置interceptor的属性\ninterceptorInstance.setProperties(properties);\n//Configuration中记录Interceptor\nconfiguration.addInterceptor(interceptorInstance);\n}\n}\n}

插件的具体使用后面专门介绍

objectFactory,objectWrapperFactory及reflectorFactory解析

privatevoidobjectFactoryElement(XNodecontext)throwsException{\nif(context!=null){\n//获取<objectFactory>节点的type属性\nStringtype=context.getStringAttribute(&34;);\n//获取<objectFactory>节点下的配置信息\nPropertiesproperties=context.getChildrenAsProperties();\n//获取ObjectFactory对象的对象通过反射方式\nObjectFactoryfactory=(ObjectFactory)resolveClass(type).getDeclaredConstructor().newInstance();\n//ObjectFactory和对应的属性信息关联\nfactory.setProperties(properties);\n//将创建的ObjectFactory对象绑定到Configuration中\nconfiguration.setObjectFactory(factory);\n}\n}\nprivatevoidobjectWrapperFactoryElement(XNodecontext)throwsException{\nif(context!=null){\nStringtype=context.getStringAttribute(&34;);\nObjectWrapperFactoryfactory=(ObjectWrapperFactory)resolveClass(type).getDeclaredConstructor().newInstance();\nconfiguration.setObjectWrapperFactory(factory);\n}\n}\nprivatevoidreflectorFactoryElement(XNodecontext)throwsException{\nif(context!=null){\nStringtype=context.getStringAttribute(&34;);\nReflectorFactoryfactory=(ReflectorFactory)resolveClass(type).getDeclaredConstructor().newInstance();\nconfiguration.setReflectorFactory(factory);\n}\n}

ObjectFactory用来创建返回的对象。

ObjectWrapperFactory用来对对象做特殊的处理。比如:select没有写别名,查询返回的是一个Map,可以在自定义的objectWrapperFactory中把下划线命名变成驼峰命名。

ReflectorFactory是反射的工具箱,对反射的操作进行了封装(官网和文档没有这个对象的描述)。

以上四个对象,都是用resolveClass创建的。

settingsElement(settings)方法

这里就是对<settings>标签里面所有子标签的处理了,前面我们已经把子标签全部转换成了Properties对象,所以在这里处理Properties对象就可以了。

settings二级标签中一共26个配置,比如二级缓存、延迟加载、默认执行器类型等等。

需要注意的是,我们之前提到的所有的默认值,都是在这里赋值的。如果说后面我们不知道这个属性的值是什么,也可以到这一步来确认一下。

所有的值,都会赋值到Configuration的属性里面去。

privatevoidsettingsElement(Propertiesprops){\nconfiguration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty(&34;,&34;)));\nconfiguration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior.valueOf(props.getProperty(&34;,&34;)));\nconfiguration.setCacheEnabled(booleanValueOf(props.getProperty(&34;),true));\nconfiguration.setProxyFactory((ProxyFactory)createInstance(props.getProperty(&34;)));\nconfiguration.setLazyLoadingEnabled(booleanValueOf(props.getProperty(&34;),false));\nconfiguration.setAggressiveLazyLoading(booleanValueOf(props.getProperty(&34;),false));\nconfiguration.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty(&34;),true));\nconfiguration.setUseColumnLabel(booleanValueOf(props.getProperty(&34;),true));\nconfiguration.setUseGeneratedKeys(booleanValueOf(props.getProperty(&34;),false));\nconfiguration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty(&34;,&34;)));\nconfiguration.setDefaultStatementTimeout(integerValueOf(props.getProperty(&34;),null));\nconfiguration.setDefaultFetchSize(integerValueOf(props.getProperty(&34;),null));\nconfiguration.setDefaultResultSetType(resolveResultSetType(props.getProperty(&34;)));\nconfiguration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty(&34;),false));\nconfiguration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty(&34;),false));\nconfiguration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty(&34;,&34;)));\nconfiguration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty(&34;,&34;)));\nconfiguration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty(&34;),&34;));\nconfiguration.setSafeResultHandlerEnabled(booleanValueOf(props.getProperty(&34;),true));\nconfiguration.setDefaultScriptingLanguage(resolveClass(props.getProperty(&34;)));\nconfiguration.setDefaultEnumTypeHandler(resolveClass(props.getProperty(&34;)));\nconfiguration.setCallSettersOnNulls(booleanValueOf(props.getProperty(&34;),false));\nconfiguration.setUseActualParamName(booleanValueOf(props.getProperty(&34;),true));\nconfiguration.setReturnInstanceForEmptyRow(booleanValueOf(props.getProperty(&34;),false));\nconfiguration.setLogPrefix(props.getProperty(&34;));\nconfiguration.setConfigurationFactory(resolveClass(props.getProperty(&34;)));\n}

environments解析

这一步是解析<environments>标签。

我们前面讲过,一个environment就是对应一个数据源,所以在这里我们会根据配置的<transactionManager>创建一个事务工厂,根据<dataSource>标签创建一个数据源,最后把这两个对象设置成Environment对象的属性,放到Configuration里面。

privatevoidenvironmentsElement(XNodecontext)throwsException{\nif(context!=null){\nif(environment==null){\nenvironment=context.getStringAttribute(&34;);\n}\nfor(XNodechild:context.getChildren()){\nStringid=child.getStringAttribute(&34;);\nif(isSpecifiedEnvironment(id)){\n//事务工厂\nTransactionFactorytxFactory=transactionManagerElement(child.evalNode(&34;));\n//数据源工厂(例如DruidDataSourceFactory)\nDataSourceFactorydsFactory=dataSourceElement(child.evalNode(&34;));\n//数据源\nDataSourcedataSource=dsFactory.getDataSource();\n//包含了事务工厂和数据源的Environment\nEnvironment.BuilderenvironmentBuilder=newEnvironment.Builder(id)\n.transactionFactory(txFactory)\n.dataSource(dataSource);\n//放入Configuration\nconfiguration.setEnvironment(environmentBuilder.build());\n}\n}\n}\n}

databaseIdProviderElement()

解析databaseIdProvider标签,生成DatabaseIdProvider对象(用来支持不同厂商的数据库)。

typeHandlerElement()

跟TypeAlias一样,TypeHandler有两种配置方式,一种是单独配置一个类,一种是指定一个package。最后我们得到的是JavaType和JdbcType,以及用来做相互映射的TypeHandler之间的映射关系,存放在TypeHandlerRegistry对象里面。

privatevoidtypeHandlerElement(XNodeparent){\nif(parent!=null){\nfor(XNodechild:parent.getChildren()){\nif(&34;.equals(child.getName())){\nStringtypeHandlerPackage=child.getStringAttribute(&34;);\ntypeHandlerRegistry.register(typeHandlerPackage);\n}else{\nStringjavaTypeName=child.getStringAttribute(&34;);\nStringjdbcTypeName=child.getStringAttribute(&34;);\nStringhandlerTypeName=child.getStringAttribute(&34;);\nClass<?>javaTypeClass=resolveClass(javaTypeName);\nJdbcTypejdbcType=resolveJdbcType(jdbcTypeName);\nClass<?>typeHandlerClass=resolveClass(handlerTypeName);\nif(javaTypeClass!=null){\nif(jdbcType==null){\ntypeHandlerRegistry.register(javaTypeClass,typeHandlerClass);\n}else{\ntypeHandlerRegistry.register(javaTypeClass,jdbcType,typeHandlerClass);\n}\n}else{\ntypeHandlerRegistry.register(typeHandlerClass);\n}\n}\n}\n}\n}

mapper解析

最后就是<mappers>标签的解析。

根据全局配置文件中不同的注册方式,用不同的方式扫描,但最终都是做了两件事情,对于语句的注册和接口的注册。

privatevoidmapperElement(XNodeparent)throwsException{\nif(parent!=null){\nfor(XNodechild:parent.getChildren()){\n//不同的定义方式的扫描,最终都是调用addMapper()方法(添加到MapperRegistry)。这个方法和getMapper()对应\n//package\t包\nif(&34;.equals(child.getName())){\nStringmapperPackage=child.getStringAttribute(&34;);\nconfiguration.addMappers(mapperPackage);\n}else{\nStringresource=child.getStringAttribute(&34;);\nStringurl=child.getStringAttribute(&34;);\nStringmapperClass=child.getStringAttribute(&34;);\nif(resource!=null&&url==null&&mapperClass==null){\n//resource\t相对路径\nErrorContext.instance().resource(resource);\nInputStreaminputStream=Resources.getResourceAsStream(resource);\nXMLMapperBuildermapperParser=newXMLMapperBuilder(inputStream,configuration,resource,configuration.getSqlFragments());\n//解析Mapper.xml,总体上做了两件事情>>\nmapperParser.parse();\n}elseif(resource==null&&url!=null&&mapperClass==null){\n//url\t绝对路径\nErrorContext.instance().resource(url);\nInputStreaminputStream=Resources.getUrlAsStream(url);\nXMLMapperBuildermapperParser=newXMLMapperBuilder(inputStream,configuration,url,configuration.getSqlFragments());\nmapperParser.parse();\n}elseif(resource==null&&url==null&&mapperClass!=null){\n//class\t单个接口\nClass<?>mapperInterface=Resources.classForName(mapperClass);\nconfiguration.addMapper(mapperInterface);\n}else{\nthrownewBuilderException(&34;);\n}\n}\n}\n}\n}

然后开始进入具体的配置文件的解析操作

2.4.2映射文件的解析

?首先进入parse方法

publicvoidparse(){\n//总体上做了两件事情,对于语句的注册和接口的注册\nif(!configuration.isResourceLoaded(resource)){\n//1、具体增删改查标签的解析。\n//一个标签一个MappedStatement。>>\nconfigurationElement(parser.evalNode(&34;));\nconfiguration.addLoadedResource(resource);\n//2、把namespace(接口类型)和工厂类绑定起来,放到一个map。\n//一个namespace一个MapperProxyFactory>>\nbindMapperForNamespace();\n}\nparsePendingResultMaps();\nparsePendingCacheRefs();\nparsePendingStatements();\n}

configurationElement()——解析所有的子标签,最终获得MappedStatement对象。

bindMapperForNamespace()——把namespace(接口类型)和工厂类MapperProxyFactory绑定起来。

configurationElement方法

?configurationElement是对Mapper.xml中所有具体的标签的解析,包括namespace、cache、parameterMap、resultMap、sql和select|insert|update|delete。

privatevoidconfigurationElement(XNodecontext){\ntry{\nStringnamespace=context.getStringAttribute(&34;);\nif(namespace==null||namespace.equals(&34;)){\nthrownewBuilderException(&39;snamespacecannotbeempty&34;cache-ref&34;cache&34;/mapper/parameterMap&34;/mapper/resultMap&34;/mapper/sql&34;select|insert|update|delete&34;ErrorparsingMapperXML.TheXMLlocationis&34;+resource+&39;.Cause:&loadXmlResource\nconfiguration.addLoadedResource(&34;+namespace);\n//添加到MapperRegistry,本质是一个map,里面也有Configuration>>\nconfiguration.addMapper(boundType);\n}\n}\n}\n}

通过源码分析发现主要是是调用了addMapper()。addMapper()方法中,把接口类型注册到MapperRegistry中:实际上是为接口创建一个对应的MapperProxyFactory(用于为这个type提供工厂类,创建MapperProxy)。

public<T>voidaddMapper(Class<T>type){\nif(type.isInterface()){//检测type是否为接口\nif(hasMapper(type)){//检测是否已经加装过该接口\nthrownewBindingException(&34;+type+&34;);\n}\nbooleanloadCompleted=false;\ntry{\n//!Map<Class<?>,MapperProxyFactory<?>>存放的是接口类型,和对应的工厂类的关系\nknownMappers.put(type,newMapperProxyFactory<>(type));\n//It&39;ttry.\n//注册了接口之后,根据接口,开始解析所有方法上的注解,例如@Select>>\nMapperAnnotationBuilderparser=newMapperAnnotationBuilder(config,type);\nparser.parse();\nloadCompleted=true;\n}finally{\nif(!loadCompleted){\nknownMappers.remove(type);\n}\n}\n}\n}

同样的再进入parse方法中查看

publicvoidparse(){\nStringresource=type.toString();\nif(!configuration.isResourceLoaded(resource)){\n//先判断Mapper.xml有没有解析,没有的话先解析Mapper.xml(例如定义package方式)\nloadXmlResource();\nconfiguration.addLoadedResource(resource);\nassistant.setCurrentNamespace(type.getName());\n//处理@CacheNamespace\nparseCache();\n//处理@CacheNamespaceRef\nparseCacheRef();\n//获取所有方法\nMethod[]methods=type.getMethods();\nfor(Methodmethod:methods){\ntry{\n//issue#237\nif(!method.isBridge()){\n//解析方法上的注解,添加到MappedStatement集合中>>\nparseStatement(method);\n}\n}catch(IncompleteElementExceptione){\nconfiguration.addIncompleteMethod(newMethodResolver(this,method));\n}\n}\n}\nparsePendingMethods();\n}

大家可以继续进入到parseStatement方法中查看。

总结:

我们主要完成了config配置文件、Mapper文件、Mapper接口中注解的解析。我们得到了一个最重要的对象Configuration,这里面存放了全部的配置信息,它在属性里面还有各种各样的容器。最后,返回了一个DefaultSqlSessionFactory,里面持有了Configuration的实例。

肝完了!1.2W字,更多Java相关资料可以关注公众号【Java大蜗牛】发送:6

好了,关于小程序素材网站解析源码分享和微信小程序素材的问题到这里结束啦,希望可以解决您的问题哈!

Published by

风君子

独自遨游何稽首 揭天掀地慰生平