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

How to integrate Mybatis in Spring

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

Share

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

How to integrate Mybatis in Spring, aiming at this problem, this article introduces the corresponding analysis and solution in detail, hoping to help more partners who want to solve this problem to find a more simple and feasible way.

The Spring integration Mybtais will be configured as follows

Private static final String ONE_MAPPER_BASE_PACKAGE = "com.XXX.dao.mapper.one"; @ Beanpublic MapperScannerConfigurer oneMapperScannerConfigurer () {MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer (); mapperScannerConfigurer.setBasePackage (ONE_MAPPER_BASE_PACKAGE); mapperScannerConfigurer. SetSqlSessionFactoryBeanName ("oneSqlSessionFactoryBean"); return mapperScannerConfigurer;} @ Primary@Bean (name= "oneSqlSessionFactoryBean") public SqlSessionFactoryBean oneSqlSessionFactoryBean (@ Qualifier ("oneDataSource") DruidDataSource oneDataSource) {return getSqlSessionFactoryBeanDruid (oneDataSource,ONE_MAPPER_XML);}

Spring integration with Mybatis was completed in less than 20 lines of code.

Amazing!!! What's going on behind this?

And start with MapperScannerConfigurer and SqlSessionFactoryBean.

MapperScannerConfigurer class comments

BeanDefinitionRegistryPostProcessor recursively searches for interfaces from base package and registers them as MapperFactoryBean. Note that the interface must contain at least one method, but the current class will be ignored.

BeanFactoryPostProcessor was extended before 1.0.1 and BeanDefinitionRegistryPostProcessor was extended after 1.0.2. For specific reasons, please refer to https://jira.springsource.org/browse/SPR-8269.

BasePackage can be configured with multiple, separated by commas or semicolons.

Through annotationClass or markerInterface, you can set the interface to specify the scan. By default, these two properties are empty and all interfaces under basePackage will be scanned.

MapperScannerConfigurer automatically injects SqlSessionFactory or SqlSessionTemplate for the bean it creates. If there is more than one SqlSessionFactory, you need to set up sqlSessionFactoryBeanName or sqlSessionTemplateBeanName to specify the specific sqlSessionFactory or sqlSessionTemplate to be injected.

You cannot pass in an object that has a placeholder (for example, an object that contains the user name and password placeholder of the database). You can use beanName to defer actual object creation until all placeholders have been replaced. Note that MapperScannerConfigurer supports the use of placeholders for its own properties, using the format ${property}.

The key method of finding class diagram

From the class diagram, MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, and BeanNameAware interfaces. The specific meanings of each API are as follows:

ApplicationContextAware: when the spring container is initialized, ApplicationContext is automatically injected

BeanNameAware: sets the name of the current Bean in Spring

The InitializingBean interface includes only the afterPropertiesSet method, which is executed when the bean is initialized

BeanDefinitionRegistryPostProcessor: an extension to BeanFactoryPostProcessor that allows multiple bean definitions to be registered before BeanFactoryPostProcessor execution. The method that needs to be extended is postProcessBeanDefinitionRegistry.

For query, the afterPropertiesSet method of MapperScannerConfigurer is as follows, and there is no specific extension information.

@ Override public void afterPropertiesSet () throws Exception {notNull (this.basePackage, "Property 'basePackage' is required");}

Combined with the annotation of MapperScannerConfigurer and the analysis of class diagram, the core method of postProcessBeanDefinitionRegistry is determined.

PostProcessBeanDefinitionRegistry Analysis @ Overridepublic void postProcessBeanDefinitionRegistry (BeanDefinitionRegistry registry) {if (this.processPropertyPlaceHolders) {/ / 1. Placeholder attributes handle processPropertyPlaceHolders ();} ClassPathMapperScanner scanner = new ClassPathMapperScanner (registry); scanner.setAddToConfig (this.addToConfig); scanner.setAnnotationClass (this.annotationClass); scanner.setMarkerInterface (this.markerInterface); scanner.setSqlSessionFactory (this.sqlSessionFactory); scanner.setSqlSessionTemplate (this.sqlSessionTemplate); scanner.setSqlSessionFactoryBeanName (this.sqlSessionFactoryBeanName); scanner.setSqlSessionTemplateBeanName (this.sqlSessionTemplateBeanName); scanner.setResourceLoader (this.applicationContext); scanner.setBeanNameGenerator (this.nameGenerator); / / 2. Set the filter scanner.registerFilters (); / / 3. Scan the java file scanner.scan (StringUtils.tokenizeToStringArray (this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));}

From the source code, we can see that except for processPropertyPlaceHolders, all other work has been entrusted to ClassPathMapperScanner.

ProcessPropertyPlaceHolders handles placeholders

It was said earlier that BeanDefinitionRegistryPostProcessor calls before the BeanFactoryPostProcessor executes

This means that the PropertyResourceConfigurer class that Spring handles placeholders hasn't been executed yet!

So how does MapperScannerConfigurer support the use of placeholders for its attributes? The answer to all this is

In the processPropertyPlaceHolders method.

Private void processPropertyPlaceHolders () {Map prcs = applicationContext.getBeansOfType (PropertyResourceConfigurer.class); if (! prcs.isEmpty () & & applicationContext instanceof GenericApplicationContext) {BeanDefinition mapperScannerBean = ((GenericApplicationContext) applicationContext) .getBeanFactory () .getBeanDefinition (beanName) / / PropertyResourceConfigurer does not expose a method to directly replace placeholders, / / create a BeanFactory that contains MapperScannerConfigurer / / and then perform BeanFactory post-processing to DefaultListableBeanFactory factory = new DefaultListableBeanFactory (); factory.registerBeanDefinition (beanName, mapperScannerBean); for (PropertyResourceConfigurer prc: prcs.values ()) {prc.postProcessBeanFactory (factory);} PropertyValues values = mapperScannerBean.getPropertyValues (); this.basePackage = updatePropertyValue ("basePackage", values) This.sqlSessionFactoryBeanName = updatePropertyValue ("sqlSessionFactoryBeanName", values); this.sqlSessionTemplateBeanName = updatePropertyValue ("sqlSessionTemplateBeanName", values);}}

After reading processPropertyPlaceHolders, you can summarize how MapperScannerConfigurer supports the use of placeholders for its own properties

Find the Bean of all registered PropertyResourceConfigurer types

Use new DefaultListableBeanFactory () to simulate the Spring environment, register MapperScannerConfigurer with the BeanFactory, and perform post-processing of BeanFactory to replace the placeholder.

RegisterFilters method of ClassPathMapperScanner

There is one of the class comments in MapperScannerConfigurer:

Through annotationClass or markerInterface, you can set the interface to be scanned. By default, these two attributes are empty, and all interfaces under basePackage will be scanned. Scanner.registerFilters () is the setting for annotationClass and markerInterface.

Public void registerFilters () {boolean acceptAllInterfaces = true; / / if annotationClass is specified, if (this.annotationClass! = null) {addIncludeFilter (new AnnotationTypeFilter (this.annotationClass)); acceptAllInterfaces = false;} / / override AssignableTypeFilter to ignore the match if (this.markerInterface! = null) {addIncludeFilter (new AssignableTypeFilter (this.markerInterface) {@ Override protected boolean matchClassName (String className) {return false) on the actual tagged interface }}); acceptAllInterfaces = false;} if (acceptAllInterfaces) {/ / handle all interfaces addIncludeFilter by default (new TypeFilter () {@ Override public boolean match (MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {return true;}}) } / / does not contain java files ending in package-info / / package-info.java package-level documentation and package-level comments addExcludeFilter (new TypeFilter () {@ Override public boolean match (MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {String className = metadataReader.getClassMetadata (). GetClassName (); return className.endsWith ("package-info");}});}

Although the filter is set, how it works in the scan depends on the scanner.scan method.

ClassPathMapperScanner's scan method public int scan (String... BasePackages) {int beanCountAtScanStart = this.registry.getBeanDefinitionCount (); doScan (basePackages); / / register the annotation configuration processor if (this.includeAnnotationConfig) {AnnotationConfigUtils. RegisterAnnotationConfigProcessors (this.registry);} return (this.registry.getBeanDefinitionCount ()-beanCountAtScanStart);}

The doScan method is as follows:

Public Set doScan (String... BasePackages) {Set beanDefinitions = super.doScan (basePackages); if (beanDefinitions.isEmpty ()) {logger.warn ("No MyBatis mapper was found in'" + Arrays.toString (basePackages) + "'package. Please check your configuration.");} else {processBeanDefinitions (beanDefinitions);} return beanDefinitions;}

The doScan method of the parent class ClassPathBeanDefinitionScanner, located in ClassPathMapperScanner, is

All java files under the scan package are converted to BeanDefinition (actually ScannedGenericBeanDefinition).

ProcessBeanDefinitions is the BeanDefinition that converts the previous BeanDefinition to MapperFactoryBean.

How does the filter work (that is, annotationClass or markerInterface)? I tracked the source code all the way.

Finally found the handling of the filter in ClassPathScanningCandidateComponentProvider's isCandidateComponent.

Protected boolean isCandidateComponent (MetadataReader metadataReader) throws IOException {for (TypeFilter tf: this.excludeFilters) {if (tf.match (metadataReader, this.metadataReaderFactory)) {return false;}} for (TypeFilter tf: this.includeFilters) {if (tf.match (metadataReader, this.metadataReaderFactory)) {return isConditionMatch (metadataReader);} return false;} summarize the role of MapperScannerConfigurer

MapperScannerConfigurer implements the postProcessBeanDefinitionRegistry method of beanDefinitionRegistryPostProcessor.

Recursively search interfaces from the directory of the specified basePackage and register them as MapperFactoryBean

SqlSessionFactoryBean class comments

Create a SqiSessionFactory for Mybatis to share in the context of Spring.

SqiSessionFactory can be injected into daos with mybatis through dependency injection.

Datasourcetransactionmanager,jtatransactionmanager and sqlsessionfactory want to combine to implement transactions.

The key method of finding class diagram

SqlSessionFactoryBean implements ApplicationListener and InitializingBean,FactoryBean interfaces. Each interface is described as follows:

Events used by ApplicationListener to listen for Spring

The InitializingBean interface includes only the afterPropertiesSet method, which is executed when the bean is initialized

FactoryBean: the object returned is not an instance of the specified class, but the object returned by the getObject method of the FactoryBean

You should focus on the methods of afterPropertiesSet and getObject.

Key method analysis

AfterPropertiesSet method

Public void afterPropertiesSet () throws Exception {notNull (dataSource, "Property 'dataSource' is required"); notNull (sqlSessionFactoryBuilder, "Property' sqlSessionFactoryBuilder' is required"); state ((configuration = = null & & configLocation = = null) | | (configuration! = null & & configLocation! = null), "Property 'configuration' and' configLocation' can not specified with together"); this.sqlSessionFactory = buildSqlSessionFactory ();}

BuildSqlSessionFactory can see that the SqlSessionFactory has been created here by looking at the method name, and the specific source code is not described in detail.

GetObject method

Public SqlSessionFactory getObject () throws Exception {if (this.sqlSessionFactory = = null) {afterPropertiesSet ();} return this.sqlSessionFactory;} Summary SqlSessionFactoryBean

Implements the afterPropertiesSet of InitializingBean, in which the SqlSessionFactory of Mybatis is created

The getObject of FactoryBean is implemented to return the created sqlSessionFactory.

Doubt

After watching this SqlSessionFactoryBean and MapperScannerConfigurer, I don't know if you have any questions! Generally speaking, the way to use Mybatis in Spring is as follows:

ApplicationContext context=new AnnotationConfigApplicationContext (); UsrMapper usrMapper=context.getBean ("usrMapper"); actually calling sqlSession.getMapper (UsrMapper.class)

SqlSessionFactoryBean created the SqlSessionFactory for Mybatis. MapperScannerConfigurer converts the interface to MapperFactoryBean. Then where is the sqlSession.getMapper (UsrMapper.class) called?

MapperFactoryBean is the answer to all this (MapperFactoryBean: look at my name-Mapper's factory! )

MapperFactoryBean description class comments

BeanFactory that can be injected into the MyBatis mapping interface. It can set SqlSessionFactory or preconfigured SqlSessionTemplate.

Note that this factory only injects interfaces, not implementation classes.

The key method of finding class diagram

If you look at the class diagram, you can see InitializingBean and FactoryBeanfolk again!

The InitializingBean interface includes only the afterPropertiesSet method, which is executed when the bean is initialized

FactoryBean: the object returned is not an instance of the specified class, but the object returned by the getObject method of the FactoryBean

Once again focus on the implementation of afterPropertiesSet and getObject!

Key method analysis

The implementation of afterPropertiesSet in the DaoSupport class is as follows:

Public final void afterPropertiesSet () throws IllegalArgumentException, BeanInitializationException {this.checkDaoConfig (); try {this.initDao ();} catch (Exception var2) {throw new BeanInitializationException ("Initialization of DAO failed", var2);}}

InitDao is an empty implementation, and checkDaoConfig has the following implementation in MapperFactoryBean:

Protected void checkDaoConfig () {super.checkDaoConfig (); notNull (this.mapperInterface, "Property 'mapperInterface' is required"); Configuration configuration = getSqlSession (). GetConfiguration (); if (this.addToConfig & &! configuration.hasMapper (this.mapperInterface)) {try {configuration.addMapper (this.mapperInterface);} catch (Exception e) {logger.error ("Error while adding the mapper'" + this.mapperInterface + "'to configuration.", e); throw new IllegalArgumentException (e) } finally {ErrorContext.instance () .reset ();}}

The key statement is configuration.addMapper (this.mapperInterface), which adds the interface to the configuration of Mybatis.

The getObject method is super simple, which calls sqlSession.getMapper (UsrMapper.class).

Public T getObject () throws Exception {return getSqlSession () .getMapper (this.mapperInterface);} Summary MapperFactoryBean

The afterPropertiesSet method of InitializingBean is implemented, in which the mapper interface is set to the configuration of mybatis.

The getObject method of FactoryBean is implemented, sqlSession.getMapper is called, and the mapper object is returned.

Summary

Spring integrates Mybatis core 3 categories:

MapperScannerConfigurer

Implements the postProcessBeanDefinitionRegistry method of beanDefinitionRegistryPostProcessor, in which the recursive search interface from the specified basePackage directory registers them as BeanDefinition of type MapperFactoryBean

SqlSessionFactoryBean

The afterPropertiesSet of InitializingBean is implemented, where the SqlSessionFactory of Mybatis is created.

The getObject of FactoryBean is implemented to return the created sqlSessionFactory.

MapperFactoryBean

The afterPropertiesSet method of InitializingBean is implemented, and the mapper interface is set to the configuration of mybatis.

The getObject method of FactoryBean is implemented, sqlSession.getMapper is called, and the mapper object is returned.

This is the answer to the question about how to integrate Mybatis in Spring. I hope the above content can be of some help to you. If you still have a lot of doubts to be solved, you can follow the industry information channel to learn more about it.

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