Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Example Analysis of MybatisSqlSessionFactoryBuilder Source Code

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/02 Report--

MybatisSqlSessionFactoryBuilder source code example analysis, many novices are not very clear about this, in order to help you solve this problem, the following editor will explain in detail for you, people with this need can come to learn, I hope you can gain something.

One: source code analysis code snippet public static void main (String [] args) {try {/ / basic mybatis environment / / 1. Define the mybatis_config file address String resources = "mybatis_config.xml"; / / 2. Get InputStreamReaderIo stream Reader reader = Resources.getResourceAsReader (resources); / / 3. Get SqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder () .build (reader); / / 4. Get Session SqlSession sqlSession = sqlSessionFactory.openSession (); / / 5. Operate the Mapper interface UserMapper mapper = sqlSession.getMapper (UserMapper.class); UserEntity user = mapper.getUser (2); System.out.println (user.getName ());} catch (Exception e) {e.printStackTrace ();}} first analyze step 2

/ / 2. Get InputStreamReaderIo stream

Reader reader = Resources.getResourceAsReader (resources)

Public static Reader getResourceAsReader (String resource) throws IOException {InputStreamReader reader; if (charset = = null) {reader = new InputStreamReader (getResourceAsStream (resource));} else {reader = new InputStreamReader (getResourceAsStream (resource), charset);} return reader;}

From the above code, we can see that the facade mode is used: the Resource class is defined, the complex process is encapsulated for convenience, and the reader is returned as InputStreamReader, which refers to the read mybatis_config.xml file. The breakpoint debugging result is as follows:

The third step is source code analysis

/ / 3. Get SqlSessionFactory

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder () .build (reader)

Enter the SqlSessionFactoryBuilder () constructor as follows:

Public SqlSessionFactoryBuilder () {}

You can see that the no-parameter constructor does nothing, then enter the build (reader) source code, and the reader parameter is InputStream stream.

Public SqlSessionFactory build (Reader reader) {return this.build ((Reader) reader, (String) null, (Properties) null);} public SqlSessionFactory build (Reader reader, String environment, Properties properties) {SqlSessionFactory var5; try {XMLConfigBuilder parser = new XMLConfigBuilder (reader, environment, properties); var5 = this.build (parser.parse ());} catch (Exception var14) {throw ExceptionFactory.wrapException ("Error building SqlSession.", var14) } finally {ErrorContext.instance (). Reset (); try {reader.close ();} catch (IOException var13) {;}} return var5;}

Let's analyze what the XMLConfigBuilder class does. Enter the XMLConfigBuilder constructor as follows:

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 ()); this.localReflectorFactory = new DefaultReflectorFactory (); ErrorContext.instance (). Resource ("SQL Mapper Configuration"); this.configuration.setVariables (props); this.parsed = false; this.environment = environment; this.parser = parser;}

Enter the super () code as follows:

Public BaseBuilder (Configuration configuration) {this.configuration = configuration; this.typeAliasRegistry = this.configuration.getTypeAliasRegistry (); this.typeHandlerRegistry = this.configuration.getTypeHandlerRegistry ();}

As can be seen from the above code: this.parsed = false; is useful, which is mentioned here first. Return to the original execution place: var5 = this.build (parser.parse ())

Var5 = this.build (parser.parse ())

Enter the parser.parse () method with the following code:

Public Configuration parse () {if (this.parsed) {throw new BuilderException ("Each XMLConfigBuilder can only be used once.");} else {this.parsed = true; this.parseConfiguration (this.parser.evalNode ("/ configuration"); return this.configuration;}}

From the previous setting of this.parsed = false, you can know that this.parsed is false, and you will enter the else branch. Readers will have questions at this time, why set this.parsed = false?

We know from the else branch that this.parsed=true is set again, indicating that the next time we enter the parse method again, this.parsed=true will directly throw an exception.

Here we can sum up:

Why can XMLConfigBuilder only be used once?

A: because our Configuration is global, it can only be parsed once.

If it is parsed multiple times, it will throw: Each XMLConfigBuilder can only be used once. Exception to prevent users from repeatedly parsing by calling the parse () method, because the configuration file is global and cannot be parsed multiple times.

Enter the following code in the else branch:

This.parseConfiguration (this.parser.evalNode ("/ configuration")); private void parseConfiguration (XNode root) {try {this.propertiesElement (root.evalNode ("properties")); this.typeAliasesElement (root.evalNode ("typeAliases")); this.pluginElement (root.evalNode ("plugins")); this.objectFactoryElement (root.evalNode ("objectFactory")); this.objectWrapperFactoryElement (root.evalNode ("objectWrapperFactory")) This.reflectionFactoryElement (root.evalNode ("reflectionFactory")); this.settingsElement (root.evalNode ("settings")); this.environmentsElement (root.evalNode ("environments")); this.databaseIdProviderElement (root.evalNode ("databaseIdProvider")); this.typeHandlerElement (root.evalNode ("typeHandlers")); this.mapperElement (root.evalNode ("mappers")) } catch (Exception var3) {throw new BuilderException ("Error parsing SQL Mapper Configuration. Cause: "+ var3, var3);}}

Let's first look at the contents of the mybatis_config.xml configuration file:

Let's start with the following line of code: since this environments is configured in our configuration file, let's analyze it first:

This.environmentsElement (root.evalNode ("environments")) private void environmentsElement (XNode context) throws Exception {if (context! = null) {if (this.environment = = null) {this.environment = context.getStringAttribute ("default");} Iterator i$ = context.getChildren (). Iterator (); while (i$.hasNext ()) {XNode child = (XNode) i$.next () String id = child.getStringAttribute ("id"); if (this.isSpecifiedEnvironment (id)) {TransactionFactory txFactory = this.transactionManagerElement (child.evalNode ("transactionManager")); DataSourceFactory dsFactory = this.dataSourceElement (child.evalNode ("dataSource")); DataSource dataSource = dsFactory.getDataSource (); Builder environmentBuilder = (new Builder (id)) .transactionFactory (txFactory) .DataSource (dataSource) This.configuration.setEnvironment (environmentBuilder.build ());}

The result of debugging environmentsElement () code through a breakpoint is as follows:

Let's take a look at this code:

This.configuration.setEnvironment (environmentBuilder.build ()); public void setEnvironment (Environment environment) {this.environment = environment;}

Here we understand: here the parsed XML node is encapsulated into an Environment object, and then the Environment object is set to the Configuration object. That is, parse XML, and then convert XML to Configuration entity class.

Let's analyze again here: the mappers node is configured in the configuration file. Let's also analyze it. The following is the content of the mapper.xml configuration file to see how it is converted into entity objects and saved:

Select * from user where id=# {id} this.mapperElement (root.evalNode ("mappers")); private void mapperElement (XNode parent) throws Exception {if (parent! = null) {Iterator i$ = parent.getChildren (). Iterator (); while (true) {while (i$.hasNext ()) {XNode child = (XNode) i$.next (); String resource If ("package" .equals (child.getName () {/ / Annotation mode configuration package resource = child.getStringAttribute ("name"); this.configuration.addMappers (resource);} else {/ / resource mode resource = child.getStringAttribute ("resource") String url = child.getStringAttribute ("url"); String mapperClass = child.getStringAttribute ("class"); XMLMapperBuilder mapperParser; InputStream inputStream; if (resource! = null & & url = = null & & mapperClass = = null) {ErrorContext.instance () .resource (resource) InputStream = Resources.getResourceAsStream (resource); mapperParser = new XMLMapperBuilder (inputStream, this.configuration, resource, this.configuration.getSqlFragments ()); mapperParser.parse ();} else if (resource = = null & & url! = null & & mapperClass = = null) {ErrorContext.instance () .resource (url) InputStream = Resources.getUrlAsStream (url); mapperParser = new XMLMapperBuilder (inputStream, this.configuration, url, this.configuration.getSqlFragments ()); mapperParser.parse () } else {if (resource! = null | | url! = null | | mapperClass = = null) {throw new BuilderException ("A mapper element may only specify a url, resource or class, but not more than one.");} Class mapperInterface = Resources.classForName (mapperClass) This.configuration.addMapper (mapperInterface);} return;}

As can be seen from the above code, there are two ways to configure the package: one is to scan the package in the form of annotations, and the other is resource.

We are configuring in resource mode, so go to the else branch:

From the above breakpoint analysis, we can see that the contents of the mapper.xml configuration file will be read, converted to an inputStream stream, and then parsed the mapper.xml configuration file

What the XMLMapperBuilder class does: parse the mapper configuration file to get the Configuration object. Let's take a look at how XMLMapperBuilder parses the mapper configuration file.

Public XMLMapperBuilder (InputStream inputStream, Configuration configuration, String resource, Map sqlFragments) {this (new XPathParser (inputStream, true, configuration.getVariables (), new XMLMapperEntityResolver ()), configuration, resource, sqlFragments);} private XMLMapperBuilder (XPathParser parser, Configuration configuration, String resource, Map sqlFragments) {super (configuration); this.builderAssistant = new MapperBuilderAssistant (configuration, resource); this.parser = parser; this.sqlFragments = sqlFragments; this.resource = resource;}

Finally enter:

MapperParser.parse () public void parse () {if (! this.configuration.isResourceLoaded (this.resource)) {this.configurationElement (this.parser.evalNode ("/ mapper")); this.configuration.addLoadedResource (this.resource); this.bindMapperForNamespace ();}

Enter the addLoadedResource () method:

Public void addLoadedResource (String resource) {this.loadedResources.add (resource);} protected final Set loadedResources;public Configuration () {this.loadedResources = new HashSet ();}

From the above code, we can see that loadedResources stores mybatis-mapped file path addresses [mapper.xml] and uses HashSet collections to store them.

After storage, the breakpoints are as follows:

Let's go into the following method:

This.bindMapperForNamespace (); private void bindMapperForNamespace () {String namespace = this.builderAssistant.getCurrentNamespace (); / / get the namespace configured in mapper.xml. Here is com.mayikt.mapper.UserMapper if (namespace! = null) {Class boundType = null; try {boundType = Resources.classForName (namespace) / / help me find it through the Java reflection mechanism. Here we get interface com.mayikt.mapper.UserMapper} catch (ClassNotFoundException var4) {;} if (boundType! = null & &! this.configuration.hasMapper (boundType)) {/ / determine whether the mapper.xml configuration file has registered this.configuration.addLoadedResource ("namespace:" + namespace); this.configuration.addMapper (boundType) }}}

Let's take a look at the addMapper method:

This.configuration.addMapper (boundType); public void addMapper (Class type) {this.mapperRegistry.addMapper (type);} public void addMapper (Class type) {if (type.isInterface ()) {/ / determine whether it is an interface type if (this.hasMapper (type)) {/ / again determine whether it has been registered, and if so, throw an exception throw new BindingException ("Type" + type + "is already known to the MapperRegistry.") } boolean loadCompleted = false; try {this.knownMappers.put (type, new MapperProxyFactory (type)); MapperAnnotationBuilder parser = new MapperAnnotationBuilder (this.config, type); parser.parse (); loadCompleted = true;} finally {if (! loadCompleted) {this.knownMappers.remove (type) } this.knownMappers.put (type, new MapperProxyFactory (type); private final Map > knownMappers = new HashMap ()

As can be seen from the above code, the function of mapperRegistry is to store the mapper interface of dao layer. The debug result is as follows:

Finally, let's take a look at what's in loadedResources: the configuration file of userMapper is stored.

And look at what's in mapperRegistery: what's stored is the mapper interface.

Finally, we go back to the original parse () method. After the above code executes the this.parseConfiguration (this.parser.evalNode ("/ configuration")) method, it returns the configuration object.

Public Configuration parse () {if (this.parsed) {throw new BuilderException ("Each XMLConfigBuilder can only be used once.");} else {this.parsed = true; this.parseConfiguration (this.parser.evalNode ("/ configuration"); return this.configuration;}}

At this point, we have finished the source code analysis. Here is a summary of the general process:

Summary:

Get the local InputStreamReader object (mybatis profile)

Call SqlSessionFactoryBuilder

# then use XMLConfigBuilder to parse the mybatis configuration file and assemble it into Configuration.

Add the Mapper in the configuration file to the Configuration mapperRegistry implementation registration.

Note: mapperRegistry stores all current mapper interfaces.

What is in loadedResources: what is stored is the configuration file of userMapper

Is it helpful for you to read the above content? If you want to know more about the relevant knowledge or read more related articles, please follow the industry information channel, thank you for your support.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report