Skip to content

Support enable/disable lazy Initialization on mapper scanning feature #377

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/main/java/org/mybatis/spring/annotation/MapperScan.java
Original file line number Diff line number Diff line change
Expand Up @@ -154,4 +154,16 @@
*/
Class<? extends MapperFactoryBean> factoryBean() default MapperFactoryBean.class;

/**
* Whether enable lazy initialization of mapper bean.
*
* <p>
* Default is {@code false}.
* </p>
*
* @return set {@code true} to enable lazy initialization
* @since 2.0.2
*/
String lazyInitialization() default "";

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
}

/**
Expand All @@ -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<? extends Annotation> 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<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
if (!BeanNameGenerator.class.equals(generatorClass)) {
scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass));
builder.addPropertyValue("nameGenerator", BeanUtils.instantiateClass(generatorClass));
}

Class<? extends MapperFactoryBean> 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<String> basePackages = new ArrayList<>();
basePackages.addAll(
Expand All @@ -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;
}

/**
Expand All @@ -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));
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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";
Expand All @@ -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<? extends Annotation> markerInterface = (Class<? extends Annotation>) classLoader
Class<? extends Annotation> annotationClass = (Class<? extends Annotation>) 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<? extends MapperFactoryBean> mapperFactoryBeanClass = (Class<? extends MapperFactoryBean>) 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;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {

private boolean addToConfig = true;

private boolean lazyInitialization;

private SqlSessionFactory sqlSessionFactory;

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

/**
* Set whether enable lazy initialization for mapper bean.
* <p>
* Default is {@code false}.
* </p>
*
* @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;
}
Expand Down Expand Up @@ -220,6 +236,7 @@ private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
LOGGER.debug(() -> "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
definition.setLazyInit(lazyInitialization);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

/**
Expand Down Expand Up @@ -93,6 +95,8 @@ public class MapperScannerConfigurer

private boolean addToConfig = true;

private String lazyInitialization;

private SqlSessionFactory sqlSessionFactory;

private SqlSessionTemplate sqlSessionTemplate;
Expand Down Expand Up @@ -140,6 +144,20 @@ public void setAddToConfig(boolean addToConfig) {
this.addToConfig = addToConfig;
}

/**
* Set whether enable lazy initialization for mapper bean.
* <p>
* Default is {@code false}.
* </p>
*
* @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.
* <p>
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,15 @@
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="lazy-initialization" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
Whether enable lazy initialization of mapper bean. Set true to enable lazy initialization. (Since 2.0.2)
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Loading