From 75c3cfff1b81948a932629c0bfafd86b31cce773 Mon Sep 17 00:00:00 2001 From: Kazuki Shimizu Date: Wed, 1 May 2019 01:05:26 +0900 Subject: [PATCH] Support enable/disable lazy Initialization on mapper scanning feature Fixes gh-376 --- .../mybatis/spring/annotation/MapperScan.java | 12 ++++ .../annotation/MapperScannerRegistrar.java | 60 ++++++++++++------ .../MapperScannerBeanDefinitionParser.java | 62 ++++++++++++------- .../spring/mapper/ClassPathMapperScanner.java | 17 +++++ .../mapper/MapperScannerConfigurer.java | 33 ++++++++++ .../mybatis/spring/config/mybatis-spring.xsd | 9 +++ .../spring/annotation/MapperScanTest.java | 55 +++++++++++++++- .../mybatis/spring/annotation/scan.properties | 17 +++++ .../mybatis/spring/config/NamespaceTest.java | 31 +++++++++- .../org/mybatis/spring/config/lazy.properties | 17 +++++ .../java/org/mybatis/spring/config/lazy.xml | 29 +++++++++ .../mapper/MapperScannerConfigurerTest.java | 46 ++++++++++++-- .../WebappPlaceholderTest.java | 11 +++- .../webapp_placeholder/conf.properties | 2 + .../submitted/webapp_placeholder/spring.xml | 1 + 15 files changed, 350 insertions(+), 52 deletions(-) rename src/main/{java => resources}/org/mybatis/spring/config/mybatis-spring.xsd (93%) create mode 100644 src/test/java/org/mybatis/spring/annotation/scan.properties create mode 100644 src/test/java/org/mybatis/spring/config/lazy.properties create mode 100644 src/test/java/org/mybatis/spring/config/lazy.xml diff --git a/src/main/java/org/mybatis/spring/annotation/MapperScan.java b/src/main/java/org/mybatis/spring/annotation/MapperScan.java index 7bdf3abccd..ee587e1775 100644 --- a/src/main/java/org/mybatis/spring/annotation/MapperScan.java +++ b/src/main/java/org/mybatis/spring/annotation/MapperScan.java @@ -154,4 +154,16 @@ */ Class factoryBean() default MapperFactoryBean.class; + /** + * Whether enable lazy initialization of mapper bean. + * + *

+ * Default is {@code false}. + *

+ * + * @return set {@code true} to enable lazy initialization + * @since 2.0.2 + */ + String lazyInitialization() default ""; + } diff --git a/src/main/java/org/mybatis/spring/annotation/MapperScannerRegistrar.java b/src/main/java/org/mybatis/spring/annotation/MapperScannerRegistrar.java index 489113930c..af99f0406f 100644 --- a/src/main/java/org/mybatis/spring/annotation/MapperScannerRegistrar.java +++ b/src/main/java/org/mybatis/spring/annotation/MapperScannerRegistrar.java @@ -19,12 +19,13 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Optional; import java.util.stream.Collectors; import org.mybatis.spring.mapper.ClassPathMapperScanner; import org.mybatis.spring.mapper.MapperFactoryBean; +import org.mybatis.spring.mapper.MapperScannerConfigurer; import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.context.ResourceLoaderAware; @@ -50,14 +51,15 @@ */ public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware { - private ResourceLoader resourceLoader; - /** * {@inheritDoc} + * + * @deprecated Since 2.0.2, this method not used never. */ @Override + @Deprecated public void setResourceLoader(ResourceLoader resourceLoader) { - this.resourceLoader = resourceLoader; + // NOP } /** @@ -68,39 +70,44 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B AnnotationAttributes mapperScanAttrs = AnnotationAttributes .fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName())); if (mapperScanAttrs != null) { - registerBeanDefinitions(mapperScanAttrs, registry); + registerBeanDefinitions(mapperScanAttrs, registry, generateBaseBeanName(importingClassMetadata, 0)); } } - void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry) { - - ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry); + void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) { - // this check is needed in Spring 3.1 - Optional.ofNullable(resourceLoader).ifPresent(scanner::setResourceLoader); + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class); + builder.addPropertyValue("processPropertyPlaceHolders", true); Class annotationClass = annoAttrs.getClass("annotationClass"); if (!Annotation.class.equals(annotationClass)) { - scanner.setAnnotationClass(annotationClass); + builder.addPropertyValue("annotationClass", annotationClass); } Class markerInterface = annoAttrs.getClass("markerInterface"); if (!Class.class.equals(markerInterface)) { - scanner.setMarkerInterface(markerInterface); + builder.addPropertyValue("markerInterface", markerInterface); } Class generatorClass = annoAttrs.getClass("nameGenerator"); if (!BeanNameGenerator.class.equals(generatorClass)) { - scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass)); + builder.addPropertyValue("nameGenerator", BeanUtils.instantiateClass(generatorClass)); } Class mapperFactoryBeanClass = annoAttrs.getClass("factoryBean"); if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) { - scanner.setMapperFactoryBeanClass(mapperFactoryBeanClass); + builder.addPropertyValue("mapperFactoryBeanClass", mapperFactoryBeanClass); } - scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef")); - scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef")); + String sqlSessionTemplateRef = annoAttrs.getString("sqlSessionTemplateRef"); + if (StringUtils.hasText(sqlSessionTemplateRef)) { + builder.addPropertyValue("sqlSessionTemplateBeanName", annoAttrs.getString("sqlSessionTemplateRef")); + } + + String sqlSessionFactoryRef = annoAttrs.getString("sqlSessionFactoryRef"); + if (StringUtils.hasText(sqlSessionFactoryRef)) { + builder.addPropertyValue("sqlSessionFactoryBeanName", annoAttrs.getString("sqlSessionFactoryRef")); + } List basePackages = new ArrayList<>(); basePackages.addAll( @@ -112,8 +119,19 @@ void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegis basePackages.addAll(Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName) .collect(Collectors.toList())); - scanner.registerFilters(); - scanner.doScan(StringUtils.toStringArray(basePackages)); + String lazyInitialization = annoAttrs.getString("lazyInitialization"); + if (StringUtils.hasText(lazyInitialization)) { + builder.addPropertyValue("lazyInitialization", lazyInitialization); + } + + builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages)); + + registry.registerBeanDefinition(beanName, builder.getBeanDefinition()); + + } + + private static String generateBaseBeanName(AnnotationMetadata importingClassMetadata, int index) { + return importingClassMetadata.getClassName() + "#" + MapperScannerRegistrar.class.getSimpleName() + "#" + index; } /** @@ -130,8 +148,10 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B AnnotationAttributes mapperScansAttrs = AnnotationAttributes .fromMap(importingClassMetadata.getAnnotationAttributes(MapperScans.class.getName())); if (mapperScansAttrs != null) { - Arrays.stream(mapperScansAttrs.getAnnotationArray("value")) - .forEach(mapperScanAttrs -> registerBeanDefinitions(mapperScanAttrs, registry)); + AnnotationAttributes[] annotations = mapperScansAttrs.getAnnotationArray("value"); + for (int i = 0; i < annotations.length; i++) { + registerBeanDefinitions(annotations[i], registry, generateBaseBeanName(importingClassMetadata, i)); + } } } } diff --git a/src/main/java/org/mybatis/spring/config/MapperScannerBeanDefinitionParser.java b/src/main/java/org/mybatis/spring/config/MapperScannerBeanDefinitionParser.java index 3fe63a2a46..ad775e21c2 100644 --- a/src/main/java/org/mybatis/spring/config/MapperScannerBeanDefinitionParser.java +++ b/src/main/java/org/mybatis/spring/config/MapperScannerBeanDefinitionParser.java @@ -19,13 +19,15 @@ import org.mybatis.spring.mapper.MapperFactoryBean; import org.mybatis.spring.mapper.ClassPathMapperScanner; +import org.mybatis.spring.mapper.MapperScannerConfigurer; import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanNameGenerator; -import org.springframework.beans.factory.xml.BeanDefinitionParser; +import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.beans.factory.xml.XmlReaderContext; -import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import org.w3c.dom.Element; @@ -38,9 +40,10 @@ * @since 1.2.0 * @see MapperFactoryBean * @see ClassPathMapperScanner + * @see MapperScannerConfigurer */ -public class MapperScannerBeanDefinitionParser implements BeanDefinitionParser { +public class MapperScannerBeanDefinitionParser extends AbstractBeanDefinitionParser { private static final String ATTRIBUTE_BASE_PACKAGE = "base-package"; private static final String ATTRIBUTE_ANNOTATION = "annotation"; @@ -49,54 +52,67 @@ public class MapperScannerBeanDefinitionParser implements BeanDefinitionParser { private static final String ATTRIBUTE_TEMPLATE_REF = "template-ref"; private static final String ATTRIBUTE_FACTORY_REF = "factory-ref"; private static final String ATTRIBUTE_MAPPER_FACTORY_BEAN_CLASS = "mapper-factory-bean-class"; + private static final String ATTRIBUTE_LAZY_INITIALIZATION = "lazy-initialization"; /** * {@inheritDoc} + * + * @since 2.0.2 */ @Override - public synchronized BeanDefinition parse(Element element, ParserContext parserContext) { - ClassPathMapperScanner scanner = new ClassPathMapperScanner(parserContext.getRegistry()); - ClassLoader classLoader = scanner.getResourceLoader().getClassLoader(); - XmlReaderContext readerContext = parserContext.getReaderContext(); - scanner.setResourceLoader(readerContext.getResourceLoader()); + protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class); + + ClassLoader classLoader = ClassUtils.getDefaultClassLoader(); + + builder.addPropertyValue("processPropertyPlaceHolders", true); try { String annotationClassName = element.getAttribute(ATTRIBUTE_ANNOTATION); if (StringUtils.hasText(annotationClassName)) { @SuppressWarnings("unchecked") - Class markerInterface = (Class) classLoader + Class annotationClass = (Class) classLoader .loadClass(annotationClassName); - scanner.setAnnotationClass(markerInterface); + builder.addPropertyValue("annotationClass", annotationClass); } String markerInterfaceClassName = element.getAttribute(ATTRIBUTE_MARKER_INTERFACE); if (StringUtils.hasText(markerInterfaceClassName)) { Class markerInterface = classLoader.loadClass(markerInterfaceClassName); - scanner.setMarkerInterface(markerInterface); + builder.addPropertyValue("markerInterface", markerInterface); } String nameGeneratorClassName = element.getAttribute(ATTRIBUTE_NAME_GENERATOR); if (StringUtils.hasText(nameGeneratorClassName)) { Class nameGeneratorClass = classLoader.loadClass(nameGeneratorClassName); BeanNameGenerator nameGenerator = BeanUtils.instantiateClass(nameGeneratorClass, BeanNameGenerator.class); - scanner.setBeanNameGenerator(nameGenerator); + builder.addPropertyValue("nameGenerator", nameGenerator); } String mapperFactoryBeanClassName = element.getAttribute(ATTRIBUTE_MAPPER_FACTORY_BEAN_CLASS); if (StringUtils.hasText(mapperFactoryBeanClassName)) { @SuppressWarnings("unchecked") Class mapperFactoryBeanClass = (Class) classLoader .loadClass(mapperFactoryBeanClassName); - scanner.setMapperFactoryBeanClass(mapperFactoryBeanClass); + builder.addPropertyValue("mapperFactoryBeanClass", mapperFactoryBeanClass); } } catch (Exception ex) { + XmlReaderContext readerContext = parserContext.getReaderContext(); readerContext.error(ex.getMessage(), readerContext.extractSource(element), ex.getCause()); } - String sqlSessionTemplateBeanName = element.getAttribute(ATTRIBUTE_TEMPLATE_REF); - scanner.setSqlSessionTemplateBeanName(sqlSessionTemplateBeanName); - String sqlSessionFactoryBeanName = element.getAttribute(ATTRIBUTE_FACTORY_REF); - scanner.setSqlSessionFactoryBeanName(sqlSessionFactoryBeanName); - scanner.registerFilters(); - String basePackage = element.getAttribute(ATTRIBUTE_BASE_PACKAGE); - scanner.scan( - StringUtils.tokenizeToStringArray(basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS)); - return null; + + builder.addPropertyValue("sqlSessionTemplateBeanName", element.getAttribute(ATTRIBUTE_TEMPLATE_REF)); + builder.addPropertyValue("sqlSessionFactoryBeanName", element.getAttribute(ATTRIBUTE_FACTORY_REF)); + builder.addPropertyValue("lazyInitialization", element.getAttribute(ATTRIBUTE_LAZY_INITIALIZATION)); + builder.addPropertyValue("basePackage", element.getAttribute(ATTRIBUTE_BASE_PACKAGE)); + + return builder.getBeanDefinition(); + } + + /** + * {@inheritDoc} + * + * @since 2.0.2 + */ + @Override + protected boolean shouldGenerateIdAsFallback() { + return true; } } diff --git a/src/main/java/org/mybatis/spring/mapper/ClassPathMapperScanner.java b/src/main/java/org/mybatis/spring/mapper/ClassPathMapperScanner.java index 4685e2a9b5..05ba5a0bef 100644 --- a/src/main/java/org/mybatis/spring/mapper/ClassPathMapperScanner.java +++ b/src/main/java/org/mybatis/spring/mapper/ClassPathMapperScanner.java @@ -55,6 +55,8 @@ public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner { private boolean addToConfig = true; + private boolean lazyInitialization; + private SqlSessionFactory sqlSessionFactory; private SqlSessionTemplate sqlSessionTemplate; @@ -81,6 +83,20 @@ public void setAnnotationClass(Class annotationClass) { this.annotationClass = annotationClass; } + /** + * Set whether enable lazy initialization for mapper bean. + *

+ * Default is {@code false}. + *

+ * + * @param lazyInitialization + * Set the @{code true} to enable + * @since 2.0.2 + */ + public void setLazyInitialization(boolean lazyInitialization) { + this.lazyInitialization = lazyInitialization; + } + public void setMarkerInterface(Class markerInterface) { this.markerInterface = markerInterface; } @@ -220,6 +236,7 @@ private void processBeanDefinitions(Set beanDefinitions) { LOGGER.debug(() -> "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'."); definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); } + definition.setLazyInit(lazyInitialization); } } diff --git a/src/main/java/org/mybatis/spring/mapper/MapperScannerConfigurer.java b/src/main/java/org/mybatis/spring/mapper/MapperScannerConfigurer.java index 886f77a436..2f83a18912 100644 --- a/src/main/java/org/mybatis/spring/mapper/MapperScannerConfigurer.java +++ b/src/main/java/org/mybatis/spring/mapper/MapperScannerConfigurer.java @@ -19,6 +19,7 @@ import java.lang.annotation.Annotation; import java.util.Map; +import java.util.Optional; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionTemplate; @@ -37,6 +38,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.env.Environment; import org.springframework.util.StringUtils; /** @@ -93,6 +95,8 @@ public class MapperScannerConfigurer private boolean addToConfig = true; + private String lazyInitialization; + private SqlSessionFactory sqlSessionFactory; private SqlSessionTemplate sqlSessionTemplate; @@ -140,6 +144,20 @@ public void setAddToConfig(boolean addToConfig) { this.addToConfig = addToConfig; } + /** + * Set whether enable lazy initialization for mapper bean. + *

+ * Default is {@code false}. + *

+ * + * @param lazyInitialization + * Set the @{code true} to enable + * @since 2.0.2 + */ + public void setLazyInitialization(String lazyInitialization) { + this.lazyInitialization = lazyInitialization; + } + /** * This property specifies the annotation that the scanner will search for. *

@@ -331,6 +349,9 @@ public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { scanner.setResourceLoader(this.applicationContext); scanner.setBeanNameGenerator(this.nameGenerator); scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass); + if (StringUtils.hasText(lazyInitialization)) { + scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization)); + } scanner.registerFilters(); scanner.scan( StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS)); @@ -364,7 +385,19 @@ private void processPropertyPlaceHolders() { this.basePackage = updatePropertyValue("basePackage", values); this.sqlSessionFactoryBeanName = updatePropertyValue("sqlSessionFactoryBeanName", values); this.sqlSessionTemplateBeanName = updatePropertyValue("sqlSessionTemplateBeanName", values); + this.lazyInitialization = updatePropertyValue("lazyInitialization", values); } + this.basePackage = Optional.ofNullable(this.basePackage).map(getEnvironment()::resolvePlaceholders).orElse(null); + this.sqlSessionFactoryBeanName = Optional.ofNullable(this.sqlSessionFactoryBeanName) + .map(getEnvironment()::resolvePlaceholders).orElse(null); + this.sqlSessionTemplateBeanName = Optional.ofNullable(this.sqlSessionTemplateBeanName) + .map(getEnvironment()::resolvePlaceholders).orElse(null); + this.lazyInitialization = Optional.ofNullable(this.lazyInitialization).map(getEnvironment()::resolvePlaceholders) + .orElse(null); + } + + private Environment getEnvironment() { + return this.applicationContext.getEnvironment(); } private String updatePropertyValue(String propertyName, PropertyValues values) { diff --git a/src/main/java/org/mybatis/spring/config/mybatis-spring.xsd b/src/main/resources/org/mybatis/spring/config/mybatis-spring.xsd similarity index 93% rename from src/main/java/org/mybatis/spring/config/mybatis-spring.xsd rename to src/main/resources/org/mybatis/spring/config/mybatis-spring.xsd index b1e87ecac5..fcd5843065 100644 --- a/src/main/java/org/mybatis/spring/config/mybatis-spring.xsd +++ b/src/main/resources/org/mybatis/spring/config/mybatis-spring.xsd @@ -130,6 +130,15 @@ + + + + + + + diff --git a/src/test/java/org/mybatis/spring/annotation/MapperScanTest.java b/src/test/java/org/mybatis/spring/annotation/MapperScanTest.java index 0c82237b51..c46f04187b 100644 --- a/src/test/java/org/mybatis/spring/annotation/MapperScanTest.java +++ b/src/test/java/org/mybatis/spring/annotation/MapperScanTest.java @@ -15,15 +15,18 @@ */ package org.mybatis.spring.annotation; -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +import org.apache.ibatis.session.SqlSessionFactory; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; +import org.mybatis.spring.annotation.mapper.ds1.Ds1Mapper; import org.mybatis.spring.mapper.AnnotatedMapper; import org.mybatis.spring.mapper.MapperInterface; import org.mybatis.spring.mapper.MapperSubinterface; @@ -36,7 +39,11 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; +import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Component; import com.mockrunner.mock.jdbc.MockDataSource; @@ -261,10 +268,39 @@ void testScanWithMapperScans() { startContext(); + SqlSessionFactory sqlSessionFactory = applicationContext.getBean(SqlSessionFactory.class); + assertEquals(2, sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers().size()); + applicationContext.getBean("ds1Mapper"); applicationContext.getBean("ds2Mapper"); } + @Test + void testLazyScanWithPropertySourcesPlaceholderConfigurer() { + applicationContext.register(LazyConfigWithPropertySourcesPlaceholderConfigurer.class); + + startContext(); + + SqlSessionFactory sqlSessionFactory = applicationContext.getBean(SqlSessionFactory.class); + assertEquals(0, sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers().size()); + applicationContext.getBean(Ds1Mapper.class); + assertEquals(1, sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers().size()); + + } + + @Test + void testLazyConfigWithPropertySource() { + applicationContext.register(LazyConfigWithPropertySource.class); + + startContext(); + + SqlSessionFactory sqlSessionFactory = applicationContext.getBean(SqlSessionFactory.class); + assertEquals(0, sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers().size()); + applicationContext.getBean(Ds1Mapper.class); + assertEquals(1, sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers().size()); + + } + @Configuration @MapperScan("org.mybatis.spring.mapper") public static class AppConfigWithPackageScan { @@ -322,6 +358,23 @@ public static class AppConfigWithMapperScanIsRepeat { public static class AppConfigWithMapperScans { } + @MapperScan(basePackages = "org.mybatis.spring.annotation.mapper.ds1", lazyInitialization = "${mybatis.lazy-initialization:false}") + public static class LazyConfigWithPropertySourcesPlaceholderConfigurer { + @Bean + static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { + PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer(); + configurer.setLocation(new ClassPathResource("/org/mybatis/spring/annotation/scan.properties")); + return configurer; + } + + } + + @MapperScan(basePackages = "org.mybatis.spring.annotation.mapper.ds1", lazyInitialization = "${mybatis.lazy-initialization:false}") + @PropertySource("classpath:/org/mybatis/spring/annotation/scan.properties") + public static class LazyConfigWithPropertySource { + + } + public static class BeanNameGenerator implements org.springframework.beans.factory.support.BeanNameGenerator { @Override diff --git a/src/test/java/org/mybatis/spring/annotation/scan.properties b/src/test/java/org/mybatis/spring/annotation/scan.properties new file mode 100644 index 0000000000..b9ab31ec7e --- /dev/null +++ b/src/test/java/org/mybatis/spring/annotation/scan.properties @@ -0,0 +1,17 @@ +# +# Copyright 2010-2019 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +mybatis.lazy-initialization=true \ No newline at end of file diff --git a/src/test/java/org/mybatis/spring/config/NamespaceTest.java b/src/test/java/org/mybatis/spring/config/NamespaceTest.java index 2da5fad503..e67c03812c 100644 --- a/src/test/java/org/mybatis/spring/config/NamespaceTest.java +++ b/src/test/java/org/mybatis/spring/config/NamespaceTest.java @@ -15,9 +15,7 @@ */ package org.mybatis.spring.config; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - +import org.apache.ibatis.session.SqlSessionFactory; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.mybatis.spring.SqlSessionFactoryBean; @@ -39,6 +37,10 @@ import com.mockrunner.mock.jdbc.MockDataSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + /** * Test for the MapperScannerRegistrar. *

@@ -78,6 +80,9 @@ void testInterfaceScan() { startContext(); + SqlSessionFactory sqlSessionFactory = applicationContext.getBean(SqlSessionFactory.class); + assertEquals(5, sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers().size()); + // all interfaces with methods should be loaded applicationContext.getBean("mapperInterface"); applicationContext.getBean("mapperSubinterface"); @@ -195,6 +200,26 @@ void testScanWithMapperFactoryBeanClass() { assertTrue(DummyMapperFactoryBean.getMapperCount() > 0); } + @Test + void testLazy() { + + applicationContext = new ClassPathXmlApplicationContext(new String[] { "org/mybatis/spring/config/lazy.xml" }, + setupSqlSessionTemplate()); + + startContext(); + + SqlSessionFactory sqlSessionFactory = applicationContext.getBean(SqlSessionFactory.class); + assertEquals(0, sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers().size()); + + // all interfaces with methods should be loaded + applicationContext.getBean("mapperInterface"); + applicationContext.getBean("mapperSubinterface"); + applicationContext.getBean("mapperChildInterface"); + applicationContext.getBean("annotatedMapper"); + + assertEquals(4, sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers().size()); + } + private GenericApplicationContext setupSqlSessionTemplate() { GenericApplicationContext genericApplicationContext = setupSqlSessionFactory(); diff --git a/src/test/java/org/mybatis/spring/config/lazy.properties b/src/test/java/org/mybatis/spring/config/lazy.properties new file mode 100644 index 0000000000..b9ab31ec7e --- /dev/null +++ b/src/test/java/org/mybatis/spring/config/lazy.properties @@ -0,0 +1,17 @@ +# +# Copyright 2010-2019 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +mybatis.lazy-initialization=true \ No newline at end of file diff --git a/src/test/java/org/mybatis/spring/config/lazy.xml b/src/test/java/org/mybatis/spring/config/lazy.xml new file mode 100644 index 0000000000..5f9e7aeffb --- /dev/null +++ b/src/test/java/org/mybatis/spring/config/lazy.xml @@ -0,0 +1,29 @@ + + + + + + + + diff --git a/src/test/java/org/mybatis/spring/mapper/MapperScannerConfigurerTest.java b/src/test/java/org/mybatis/spring/mapper/MapperScannerConfigurerTest.java index a85cef06e0..393cd4c1f5 100644 --- a/src/test/java/org/mybatis/spring/mapper/MapperScannerConfigurerTest.java +++ b/src/test/java/org/mybatis/spring/mapper/MapperScannerConfigurerTest.java @@ -16,6 +16,7 @@ package org.mybatis.spring.mapper; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -89,6 +90,10 @@ void assertNoMapperClass() { void testInterfaceScan() { startContext(); + SqlSessionFactory sqlSessionFactory = applicationContext.getBean(SqlSessionFactory.class); + + assertEquals(5, sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers().size()); + // all interfaces with methods should be loaded applicationContext.getBean("mapperInterface"); applicationContext.getBean("mapperSubinterface"); @@ -166,7 +171,13 @@ void testScanWithExplicitSqlSessionFactory() { applicationContext.getBeanDefinition("mapperScanner").getPropertyValues().add("sqlSessionFactoryBeanName", "sqlSessionFactory2"); - testInterfaceScan(); + startContext(); + + // all interfaces with methods should be loaded + applicationContext.getBean("mapperInterface"); + applicationContext.getBean("mapperSubinterface"); + applicationContext.getBean("mapperChildInterface"); + applicationContext.getBean("annotatedMapper"); } @Test @@ -181,7 +192,13 @@ void testScanWithExplicitSqlSessionTemplate() { applicationContext.getBeanDefinition("mapperScanner").getPropertyValues().add("sqlSessionTemplateBeanName", "sqlSessionTemplate"); - testInterfaceScan(); + startContext(); + + // all interfaces with methods should be loaded + applicationContext.getBean("mapperInterface"); + applicationContext.getBean("mapperSubinterface"); + applicationContext.getBean("mapperChildInterface"); + applicationContext.getBean("annotatedMapper"); } @Test @@ -201,7 +218,13 @@ void testScanWithExplicitSqlSessionFactoryViaPlaceholder() { applicationContext.registerBeanDefinition("propertiesPlaceholder", propertyDefinition); - testInterfaceScan(); + startContext(); + + // all interfaces with methods should be loaded + applicationContext.getBean("mapperInterface"); + applicationContext.getBean("mapperSubinterface"); + applicationContext.getBean("mapperChildInterface"); + applicationContext.getBean("annotatedMapper"); } @Test @@ -224,6 +247,8 @@ void testScanWithPropertyPlaceholders() { definition.getPropertyValues().removePropertyValue("basePackage"); definition.getPropertyValues().add("basePackage", "${basePackageProperty}"); definition.getPropertyValues().add("processPropertyPlaceHolders", true); + // for lazy initialization + definition.getPropertyValues().add("lazyInitialization", "${mybatis.lazy-initialization:false}"); // also use a property placeholder for an SqlSessionFactory property // to make sure the configLocation was setup correctly and MapperScanner did not change @@ -235,6 +260,7 @@ void testScanWithPropertyPlaceholders() { Properties props = new java.util.Properties(); props.put("basePackageProperty", "org.mybatis.spring.mapper"); props.put("configLocationProperty", "classpath:org/mybatis/spring/mybatis-config.xml"); + props.put("mybatis.lazy-initialization", "true"); GenericBeanDefinition propertyDefinition = new GenericBeanDefinition(); propertyDefinition.setBeanClass(PropertyPlaceholderConfigurer.class); @@ -242,7 +268,19 @@ void testScanWithPropertyPlaceholders() { applicationContext.registerBeanDefinition("propertiesPlaceholder", propertyDefinition); - testInterfaceScan(); + startContext(); + + SqlSessionFactory sqlSessionFactory = applicationContext.getBean(SqlSessionFactory.class); + System.out.println(sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers()); + assertEquals(1, sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers().size()); + + // all interfaces with methods should be loaded + applicationContext.getBean("mapperInterface"); + applicationContext.getBean("mapperSubinterface"); + applicationContext.getBean("mapperChildInterface"); + applicationContext.getBean("annotatedMapper"); + + assertEquals(5, sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers().size()); // make sure the configLocation was setup correctly // mybatis-config.xml changes the executor from the default SIMPLE type diff --git a/src/test/java/org/mybatis/spring/submitted/webapp_placeholder/WebappPlaceholderTest.java b/src/test/java/org/mybatis/spring/submitted/webapp_placeholder/WebappPlaceholderTest.java index 9ba579f7c0..0562d3444d 100644 --- a/src/test/java/org/mybatis/spring/submitted/webapp_placeholder/WebappPlaceholderTest.java +++ b/src/test/java/org/mybatis/spring/submitted/webapp_placeholder/WebappPlaceholderTest.java @@ -17,9 +17,12 @@ import static org.assertj.core.api.Assertions.assertThat; +import org.apache.ibatis.session.SqlSessionFactory; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; import org.springframework.test.context.web.WebAppConfiguration; @@ -30,10 +33,16 @@ class WebappPlaceholderTest { @Autowired - private Mapper mapper; + private SqlSessionFactory sqlSessionFactory; + + @Autowired + private ApplicationContext applicationContext; @Test void testName() { + Assertions.assertEquals(0, sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers().size()); + Mapper mapper = applicationContext.getBean(Mapper.class); assertThat(mapper).isNotNull(); + Assertions.assertEquals(1, sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers().size()); } } diff --git a/src/test/java/org/mybatis/spring/submitted/webapp_placeholder/conf.properties b/src/test/java/org/mybatis/spring/submitted/webapp_placeholder/conf.properties index ec1b941cb0..16f70c3dad 100644 --- a/src/test/java/org/mybatis/spring/submitted/webapp_placeholder/conf.properties +++ b/src/test/java/org/mybatis/spring/submitted/webapp_placeholder/conf.properties @@ -15,3 +15,5 @@ # basePkg=org.mybatis.spring.submitted.webapp_placeholder + +mybatis.lazy-initialization=true diff --git a/src/test/java/org/mybatis/spring/submitted/webapp_placeholder/spring.xml b/src/test/java/org/mybatis/spring/submitted/webapp_placeholder/spring.xml index 8942482467..379bb64429 100644 --- a/src/test/java/org/mybatis/spring/submitted/webapp_placeholder/spring.xml +++ b/src/test/java/org/mybatis/spring/submitted/webapp_placeholder/spring.xml @@ -36,6 +36,7 @@ +