Skip to content

Commit 37d1eea

Browse files
committed
Support enable/disable lazy Initialization on mapper scanning feature
Fixes mybatisgh-376
1 parent 09e405f commit 37d1eea

File tree

15 files changed

+350
-52
lines changed

15 files changed

+350
-52
lines changed

src/main/java/org/mybatis/spring/annotation/MapperScan.java

+12
Original file line numberDiff line numberDiff line change
@@ -154,4 +154,16 @@
154154
*/
155155
Class<? extends MapperFactoryBean> factoryBean() default MapperFactoryBean.class;
156156

157+
/**
158+
* Whether enable lazy initialization of mapper bean.
159+
*
160+
* <p>
161+
* Default is {@code false}.
162+
* </p>
163+
*
164+
* @return set {@code true} to enable lazy initialization
165+
* @since 2.0.2
166+
*/
167+
String lazyInitialization() default "";
168+
157169
}

src/main/java/org/mybatis/spring/annotation/MapperScannerRegistrar.java

+40-20
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,13 @@
1919
import java.util.ArrayList;
2020
import java.util.Arrays;
2121
import java.util.List;
22-
import java.util.Optional;
2322
import java.util.stream.Collectors;
2423

2524
import org.mybatis.spring.mapper.ClassPathMapperScanner;
2625
import org.mybatis.spring.mapper.MapperFactoryBean;
26+
import org.mybatis.spring.mapper.MapperScannerConfigurer;
2727
import org.springframework.beans.BeanUtils;
28+
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
2829
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
2930
import org.springframework.beans.factory.support.BeanNameGenerator;
3031
import org.springframework.context.ResourceLoaderAware;
@@ -50,14 +51,15 @@
5051
*/
5152
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
5253

53-
private ResourceLoader resourceLoader;
54-
5554
/**
5655
* {@inheritDoc}
56+
*
57+
* @deprecated Since 2.0.2, this method not used never.
5758
*/
5859
@Override
60+
@Deprecated
5961
public void setResourceLoader(ResourceLoader resourceLoader) {
60-
this.resourceLoader = resourceLoader;
62+
// NOP
6163
}
6264

6365
/**
@@ -68,39 +70,44 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B
6870
AnnotationAttributes mapperScanAttrs = AnnotationAttributes
6971
.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
7072
if (mapperScanAttrs != null) {
71-
registerBeanDefinitions(mapperScanAttrs, registry);
73+
registerBeanDefinitions(mapperScanAttrs, registry, generateBaseBeanName(importingClassMetadata, 0));
7274
}
7375
}
7476

75-
void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry) {
76-
77-
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
77+
void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) {
7878

79-
// this check is needed in Spring 3.1
80-
Optional.ofNullable(resourceLoader).ifPresent(scanner::setResourceLoader);
79+
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
80+
builder.addPropertyValue("processPropertyPlaceHolders", true);
8181

8282
Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
8383
if (!Annotation.class.equals(annotationClass)) {
84-
scanner.setAnnotationClass(annotationClass);
84+
builder.addPropertyValue("annotationClass", annotationClass);
8585
}
8686

8787
Class<?> markerInterface = annoAttrs.getClass("markerInterface");
8888
if (!Class.class.equals(markerInterface)) {
89-
scanner.setMarkerInterface(markerInterface);
89+
builder.addPropertyValue("markerInterface", markerInterface);
9090
}
9191

9292
Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
9393
if (!BeanNameGenerator.class.equals(generatorClass)) {
94-
scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass));
94+
builder.addPropertyValue("nameGenerator", BeanUtils.instantiateClass(generatorClass));
9595
}
9696

9797
Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
9898
if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
99-
scanner.setMapperFactoryBeanClass(mapperFactoryBeanClass);
99+
builder.addPropertyValue("mapperFactoryBeanClass", mapperFactoryBeanClass);
100100
}
101101

102-
scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
103-
scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));
102+
String sqlSessionTemplateRef = annoAttrs.getString("sqlSessionTemplateRef");
103+
if (StringUtils.hasText(sqlSessionTemplateRef)) {
104+
builder.addPropertyValue("sqlSessionTemplateBeanName", annoAttrs.getString("sqlSessionTemplateRef"));
105+
}
106+
107+
String sqlSessionFactoryRef = annoAttrs.getString("sqlSessionFactoryRef");
108+
if (StringUtils.hasText(sqlSessionFactoryRef)) {
109+
builder.addPropertyValue("sqlSessionFactoryBeanName", annoAttrs.getString("sqlSessionFactoryRef"));
110+
}
104111

105112
List<String> basePackages = new ArrayList<>();
106113
basePackages.addAll(
@@ -112,8 +119,19 @@ void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegis
112119
basePackages.addAll(Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName)
113120
.collect(Collectors.toList()));
114121

115-
scanner.registerFilters();
116-
scanner.doScan(StringUtils.toStringArray(basePackages));
122+
String lazyInitialization = annoAttrs.getString("lazyInitialization");
123+
if (StringUtils.hasText(lazyInitialization)) {
124+
builder.addPropertyValue("lazyInitialization", lazyInitialization);
125+
}
126+
127+
builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages));
128+
129+
registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
130+
131+
}
132+
133+
private static String generateBaseBeanName(AnnotationMetadata importingClassMetadata, int index) {
134+
return importingClassMetadata.getClassName() + "#" + MapperScannerRegistrar.class.getSimpleName() + "#" + index;
117135
}
118136

119137
/**
@@ -130,8 +148,10 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B
130148
AnnotationAttributes mapperScansAttrs = AnnotationAttributes
131149
.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScans.class.getName()));
132150
if (mapperScansAttrs != null) {
133-
Arrays.stream(mapperScansAttrs.getAnnotationArray("value"))
134-
.forEach(mapperScanAttrs -> registerBeanDefinitions(mapperScanAttrs, registry));
151+
AnnotationAttributes[] annotations = mapperScansAttrs.getAnnotationArray("value");
152+
for (int i = 0; i < annotations.length; i++) {
153+
registerBeanDefinitions(annotations[i], registry, generateBaseBeanName(importingClassMetadata, i));
154+
}
135155
}
136156
}
137157
}

src/main/java/org/mybatis/spring/config/MapperScannerBeanDefinitionParser.java

+39-23
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@
1919

2020
import org.mybatis.spring.mapper.MapperFactoryBean;
2121
import org.mybatis.spring.mapper.ClassPathMapperScanner;
22+
import org.mybatis.spring.mapper.MapperScannerConfigurer;
2223
import org.springframework.beans.BeanUtils;
23-
import org.springframework.beans.factory.config.BeanDefinition;
24+
import org.springframework.beans.factory.support.AbstractBeanDefinition;
25+
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
2426
import org.springframework.beans.factory.support.BeanNameGenerator;
25-
import org.springframework.beans.factory.xml.BeanDefinitionParser;
27+
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
2628
import org.springframework.beans.factory.xml.ParserContext;
2729
import org.springframework.beans.factory.xml.XmlReaderContext;
28-
import org.springframework.context.ConfigurableApplicationContext;
30+
import org.springframework.util.ClassUtils;
2931
import org.springframework.util.StringUtils;
3032
import org.w3c.dom.Element;
3133

@@ -38,9 +40,10 @@
3840
* @since 1.2.0
3941
* @see MapperFactoryBean
4042
* @see ClassPathMapperScanner
43+
* @see MapperScannerConfigurer
4144
*/
4245

43-
public class MapperScannerBeanDefinitionParser implements BeanDefinitionParser {
46+
public class MapperScannerBeanDefinitionParser extends AbstractBeanDefinitionParser {
4447

4548
private static final String ATTRIBUTE_BASE_PACKAGE = "base-package";
4649
private static final String ATTRIBUTE_ANNOTATION = "annotation";
@@ -49,54 +52,67 @@ public class MapperScannerBeanDefinitionParser implements BeanDefinitionParser {
4952
private static final String ATTRIBUTE_TEMPLATE_REF = "template-ref";
5053
private static final String ATTRIBUTE_FACTORY_REF = "factory-ref";
5154
private static final String ATTRIBUTE_MAPPER_FACTORY_BEAN_CLASS = "mapper-factory-bean-class";
55+
private static final String ATTRIBUTE_LAZY_INITIALIZATION = "lazy-initialization";
5256

5357
/**
5458
* {@inheritDoc}
59+
*
60+
* @since 2.0.2
5561
*/
5662
@Override
57-
public synchronized BeanDefinition parse(Element element, ParserContext parserContext) {
58-
ClassPathMapperScanner scanner = new ClassPathMapperScanner(parserContext.getRegistry());
59-
ClassLoader classLoader = scanner.getResourceLoader().getClassLoader();
60-
XmlReaderContext readerContext = parserContext.getReaderContext();
61-
scanner.setResourceLoader(readerContext.getResourceLoader());
63+
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
64+
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
65+
66+
ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
67+
68+
builder.addPropertyValue("processPropertyPlaceHolders", true);
6269
try {
6370
String annotationClassName = element.getAttribute(ATTRIBUTE_ANNOTATION);
6471
if (StringUtils.hasText(annotationClassName)) {
6572
@SuppressWarnings("unchecked")
66-
Class<? extends Annotation> markerInterface = (Class<? extends Annotation>) classLoader
73+
Class<? extends Annotation> annotationClass = (Class<? extends Annotation>) classLoader
6774
.loadClass(annotationClassName);
68-
scanner.setAnnotationClass(markerInterface);
75+
builder.addPropertyValue("annotationClass", annotationClass);
6976
}
7077
String markerInterfaceClassName = element.getAttribute(ATTRIBUTE_MARKER_INTERFACE);
7178
if (StringUtils.hasText(markerInterfaceClassName)) {
7279
Class<?> markerInterface = classLoader.loadClass(markerInterfaceClassName);
73-
scanner.setMarkerInterface(markerInterface);
80+
builder.addPropertyValue("markerInterface", markerInterface);
7481
}
7582
String nameGeneratorClassName = element.getAttribute(ATTRIBUTE_NAME_GENERATOR);
7683
if (StringUtils.hasText(nameGeneratorClassName)) {
7784
Class<?> nameGeneratorClass = classLoader.loadClass(nameGeneratorClassName);
7885
BeanNameGenerator nameGenerator = BeanUtils.instantiateClass(nameGeneratorClass, BeanNameGenerator.class);
79-
scanner.setBeanNameGenerator(nameGenerator);
86+
builder.addPropertyValue("nameGenerator", nameGenerator);
8087
}
8188
String mapperFactoryBeanClassName = element.getAttribute(ATTRIBUTE_MAPPER_FACTORY_BEAN_CLASS);
8289
if (StringUtils.hasText(mapperFactoryBeanClassName)) {
8390
@SuppressWarnings("unchecked")
8491
Class<? extends MapperFactoryBean> mapperFactoryBeanClass = (Class<? extends MapperFactoryBean>) classLoader
8592
.loadClass(mapperFactoryBeanClassName);
86-
scanner.setMapperFactoryBeanClass(mapperFactoryBeanClass);
93+
builder.addPropertyValue("mapperFactoryBeanClass", mapperFactoryBeanClass);
8794
}
8895
} catch (Exception ex) {
96+
XmlReaderContext readerContext = parserContext.getReaderContext();
8997
readerContext.error(ex.getMessage(), readerContext.extractSource(element), ex.getCause());
9098
}
91-
String sqlSessionTemplateBeanName = element.getAttribute(ATTRIBUTE_TEMPLATE_REF);
92-
scanner.setSqlSessionTemplateBeanName(sqlSessionTemplateBeanName);
93-
String sqlSessionFactoryBeanName = element.getAttribute(ATTRIBUTE_FACTORY_REF);
94-
scanner.setSqlSessionFactoryBeanName(sqlSessionFactoryBeanName);
95-
scanner.registerFilters();
96-
String basePackage = element.getAttribute(ATTRIBUTE_BASE_PACKAGE);
97-
scanner.scan(
98-
StringUtils.tokenizeToStringArray(basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
99-
return null;
99+
100+
builder.addPropertyValue("sqlSessionTemplateBeanName", element.getAttribute(ATTRIBUTE_TEMPLATE_REF));
101+
builder.addPropertyValue("sqlSessionFactoryBeanName", element.getAttribute(ATTRIBUTE_FACTORY_REF));
102+
builder.addPropertyValue("lazyInitialization", element.getAttribute(ATTRIBUTE_LAZY_INITIALIZATION));
103+
builder.addPropertyValue("basePackage", element.getAttribute(ATTRIBUTE_BASE_PACKAGE));
104+
105+
return builder.getBeanDefinition();
106+
}
107+
108+
/**
109+
* {@inheritDoc}
110+
*
111+
* @since 2.0.2
112+
*/
113+
@Override
114+
protected boolean shouldGenerateIdAsFallback() {
115+
return true;
100116
}
101117

102118
}

src/main/java/org/mybatis/spring/mapper/ClassPathMapperScanner.java

+17
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
5555

5656
private boolean addToConfig = true;
5757

58+
private boolean lazyInitialization;
59+
5860
private SqlSessionFactory sqlSessionFactory;
5961

6062
private SqlSessionTemplate sqlSessionTemplate;
@@ -81,6 +83,20 @@ public void setAnnotationClass(Class<? extends Annotation> annotationClass) {
8183
this.annotationClass = annotationClass;
8284
}
8385

86+
/**
87+
* Set whether enable lazy initialization for mapper bean.
88+
* <p>
89+
* Default is {@code false}.
90+
* </p>
91+
*
92+
* @param lazyInitialization
93+
* Set the @{code true} to enable
94+
* @since 2.0.2
95+
*/
96+
public void setLazyInitialization(boolean lazyInitialization) {
97+
this.lazyInitialization = lazyInitialization;
98+
}
99+
84100
public void setMarkerInterface(Class<?> markerInterface) {
85101
this.markerInterface = markerInterface;
86102
}
@@ -220,6 +236,7 @@ private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
220236
LOGGER.debug(() -> "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
221237
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
222238
}
239+
definition.setLazyInit(lazyInitialization);
223240
}
224241
}
225242

src/main/java/org/mybatis/spring/mapper/MapperScannerConfigurer.java

+33
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import java.lang.annotation.Annotation;
2121
import java.util.Map;
22+
import java.util.Optional;
2223

2324
import org.apache.ibatis.session.SqlSessionFactory;
2425
import org.mybatis.spring.SqlSessionTemplate;
@@ -37,6 +38,7 @@
3738
import org.springframework.context.ApplicationContext;
3839
import org.springframework.context.ApplicationContextAware;
3940
import org.springframework.context.ConfigurableApplicationContext;
41+
import org.springframework.core.env.Environment;
4042
import org.springframework.util.StringUtils;
4143

4244
/**
@@ -93,6 +95,8 @@ public class MapperScannerConfigurer
9395

9496
private boolean addToConfig = true;
9597

98+
private String lazyInitialization;
99+
96100
private SqlSessionFactory sqlSessionFactory;
97101

98102
private SqlSessionTemplate sqlSessionTemplate;
@@ -140,6 +144,20 @@ public void setAddToConfig(boolean addToConfig) {
140144
this.addToConfig = addToConfig;
141145
}
142146

147+
/**
148+
* Set whether enable lazy initialization for mapper bean.
149+
* <p>
150+
* Default is {@code false}.
151+
* </p>
152+
*
153+
* @param lazyInitialization
154+
* Set the @{code true} to enable
155+
* @since 2.0.2
156+
*/
157+
public void setLazyInitialization(String lazyInitialization) {
158+
this.lazyInitialization = lazyInitialization;
159+
}
160+
143161
/**
144162
* This property specifies the annotation that the scanner will search for.
145163
* <p>
@@ -331,6 +349,9 @@ public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
331349
scanner.setResourceLoader(this.applicationContext);
332350
scanner.setBeanNameGenerator(this.nameGenerator);
333351
scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
352+
if (StringUtils.hasText(lazyInitialization)) {
353+
scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
354+
}
334355
scanner.registerFilters();
335356
scanner.scan(
336357
StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
@@ -364,7 +385,19 @@ private void processPropertyPlaceHolders() {
364385
this.basePackage = updatePropertyValue("basePackage", values);
365386
this.sqlSessionFactoryBeanName = updatePropertyValue("sqlSessionFactoryBeanName", values);
366387
this.sqlSessionTemplateBeanName = updatePropertyValue("sqlSessionTemplateBeanName", values);
388+
this.lazyInitialization = updatePropertyValue("lazyInitialization", values);
367389
}
390+
this.basePackage = Optional.ofNullable(this.basePackage).map(getEnvironment()::resolvePlaceholders).orElse(null);
391+
this.sqlSessionFactoryBeanName = Optional.ofNullable(this.sqlSessionFactoryBeanName)
392+
.map(getEnvironment()::resolvePlaceholders).orElse(null);
393+
this.sqlSessionTemplateBeanName = Optional.ofNullable(this.sqlSessionTemplateBeanName)
394+
.map(getEnvironment()::resolvePlaceholders).orElse(null);
395+
this.lazyInitialization = Optional.ofNullable(this.lazyInitialization).map(getEnvironment()::resolvePlaceholders)
396+
.orElse(null);
397+
}
398+
399+
private Environment getEnvironment() {
400+
return this.applicationContext.getEnvironment();
368401
}
369402

370403
private String updatePropertyValue(String propertyName, PropertyValues values) {

src/main/java/org/mybatis/spring/config/mybatis-spring.xsd renamed to src/main/resources/org/mybatis/spring/config/mybatis-spring.xsd

+9
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,15 @@
130130
</xsd:appinfo>
131131
</xsd:annotation>
132132
</xsd:attribute>
133+
<xsd:attribute name="lazy-initialization" type="xsd:string">
134+
<xsd:annotation>
135+
<xsd:documentation>
136+
<![CDATA[
137+
Whether enable lazy initialization of mapper bean. Set true to enable lazy initialization. (Since 2.0.2)
138+
]]>
139+
</xsd:documentation>
140+
</xsd:annotation>
141+
</xsd:attribute>
133142
</xsd:complexType>
134143
</xsd:element>
135144
</xsd:schema>

0 commit comments

Comments
 (0)