Skip to content
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

Support scoped proxy on mapper scan feature #484

Merged
merged 1 commit into from
Jun 21, 2020
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
18 changes: 15 additions & 3 deletions src/main/java/org/mybatis/spring/annotation/MapperScan.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,14 @@

import org.mybatis.spring.mapper.MapperFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.annotation.Import;

/**
* Use this annotation to register MyBatis mapper interfaces when using Java Config. It performs when same work as
* {@link MapperScannerConfigurer} via {@link MapperScannerRegistrar}.
*
*
* <p>
* Either {@link #basePackageClasses} or {@link #basePackages} (or its alias {@link #value}) may be specified to define
* specific packages to scan. Since 2.0.4, If specific packages are not defined, scanning will occur from the package of
Expand All @@ -40,7 +41,7 @@
* <p>
* Configuration example:
* </p>
*
*
* <pre class="code">
* &#064;Configuration
* &#064;MapperScan("org.mybatis.spring.sample.mapper")
Expand Down Expand Up @@ -165,10 +166,21 @@
* <p>
* Default is {@code false}.
* </p>
*
*
* @return set {@code true} to enable lazy initialization
* @since 2.0.2
*/
String lazyInitialization() default "";

/**
* Specifies the default scope of scanned mappers.
*
* <p>
* Default is {@code ""} (equiv to singleton).
* </p>
*
* @return the default scope
*/
String defaultScope() default AbstractBeanDefinition.SCOPE_DEFAULT;

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.mybatis.spring.mapper.MapperFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
Expand Down Expand Up @@ -53,7 +54,7 @@ public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, Re

/**
* {@inheritDoc}
*
*
* @deprecated Since 2.0.2, this method not used never.
*/
@Override
Expand Down Expand Up @@ -130,6 +131,11 @@ void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes a
builder.addPropertyValue("lazyInitialization", lazyInitialization);
}

String defaultScope = annoAttrs.getString("defaultScope");
if (!AbstractBeanDefinition.SCOPE_DEFAULT.equals(defaultScope)) {
builder.addPropertyValue("defaultScope", defaultScope);
}

builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages));

registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
Expand All @@ -146,7 +152,7 @@ private static String getDefaultBasePackage(AnnotationMetadata importingClassMet

/**
* A {@link MapperScannerRegistrar} for {@link MapperScans}.
*
*
* @since 2.0.0
*/
static class RepeatingRegistrar extends MapperScannerRegistrar {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2010-2019 the original author or authors.
* Copyright 2010-2020 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.
Expand All @@ -17,8 +17,8 @@

import java.lang.annotation.Annotation;

import org.mybatis.spring.mapper.MapperFactoryBean;
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.AbstractBeanDefinition;
Expand All @@ -33,7 +33,7 @@

/**
* A {#code BeanDefinitionParser} that handles the element scan of the MyBatis. namespace
*
*
* @author Lishu Luo
* @author Eduardo Macarron
*
Expand All @@ -53,10 +53,11 @@ public class MapperScannerBeanDefinitionParser extends AbstractBeanDefinitionPar
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";
private static final String ATTRIBUTE_DEFAULT_SCOPE = "default-scope";

/**
* {@inheritDoc}
*
*
* @since 2.0.2
*/
@Override
Expand Down Expand Up @@ -100,14 +101,15 @@ protected AbstractBeanDefinition parseInternal(Element element, ParserContext pa
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("defaultScope", element.getAttribute(ATTRIBUTE_DEFAULT_SCOPE));
builder.addPropertyValue("basePackage", element.getAttribute(ATTRIBUTE_BASE_PACKAGE));

return builder.getBeanDefinition();
}

/**
* {@inheritDoc}
*
*
* @since 2.0.2
*/
@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2010-2019 the original author or authors.
* Copyright 2010-2020 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.
Expand All @@ -15,26 +15,30 @@
*/
package org.mybatis.spring.mapper;

import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Optional;
import java.util.Set;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.logging.Logger;
import org.mybatis.logging.LoggerFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.aop.scope.ScopedProxyFactoryBean;
import org.springframework.aop.scope.ScopedProxyUtils;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.util.StringUtils;

import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Set;

/**
* A {@link ClassPathBeanDefinitionScanner} that registers Mappers by {@code basePackage}, {@code annotationClass}, or
* {@code markerInterface}. If an {@code annotationClass} and/or {@code markerInterface} is specified, only the
Expand All @@ -45,7 +49,7 @@
*
* @author Hunter Presnall
* @author Eduardo Macarron
*
*
* @see MapperFactoryBean
* @since 1.2.0
*/
Expand All @@ -71,6 +75,8 @@ public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {

private Class<? extends MapperFactoryBean> mapperFactoryBeanClass = MapperFactoryBean.class;

private String defaultScope;

public ClassPathMapperScanner(BeanDefinitionRegistry registry) {
super(registry, false);
}
Expand Down Expand Up @@ -136,6 +142,20 @@ public void setMapperFactoryBeanClass(Class<? extends MapperFactoryBean> mapperF
this.mapperFactoryBeanClass = mapperFactoryBeanClass == null ? MapperFactoryBean.class : mapperFactoryBeanClass;
}

/**
* Set the default scope of scanned mappers.
* <p>
* Default is {@code null} (equiv to singleton).
* </p>
*
* @param defaultScope
* the scope
* @since 2.0.6
*/
public void setDefaultScope(String defaultScope) {
this.defaultScope = defaultScope;
}

/**
* Configures parent scanner to search for the right interfaces. It can search for all interfaces or just for those
* that extends a markerInterface or/and those annotated with the annotationClass
Expand Down Expand Up @@ -191,9 +211,18 @@ public Set<BeanDefinitionHolder> doScan(String... basePackages) {
}

private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
AbstractBeanDefinition definition;
BeanDefinitionRegistry registry = getRegistry();
for (BeanDefinitionHolder holder : beanDefinitions) {
definition = (GenericBeanDefinition) holder.getBeanDefinition();
definition = (AbstractBeanDefinition) holder.getBeanDefinition();
boolean scopedProxy = false;
if (ScopedProxyFactoryBean.class.getName().equals(definition.getBeanClassName())) {
definition = (AbstractBeanDefinition) Optional
.ofNullable(((RootBeanDefinition) definition).getDecoratedDefinition())
.map(BeanDefinitionHolder::getBeanDefinition).orElseThrow(() -> new IllegalStateException(
"The target bean definition of scoped proxy bean not found. Root bean definition[" + holder + "]"));
scopedProxy = true;
}
String beanClassName = definition.getBeanClassName();
LOGGER.debug(() -> "Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + beanClassName
+ "' mapperInterface");
Expand Down Expand Up @@ -236,7 +265,25 @@ 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);

if (scopedProxy) {
continue;
}

if (ConfigurableBeanFactory.SCOPE_SINGLETON.equals(definition.getScope()) && defaultScope != null) {
definition.setScope(defaultScope);
}

if (!definition.isSingleton()) {
BeanDefinitionHolder proxyHolder = ScopedProxyUtils.createScopedProxy(holder, registry, true);
if (registry.containsBeanDefinition(proxyHolder.getBeanName())) {
registry.removeBeanDefinition(proxyHolder.getBeanName());
}
registry.registerBeanDefinition(proxyHolder.getBeanName(), proxyHolder.getBeanDefinition());
}

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ public class MapperScannerConfigurer

private BeanNameGenerator nameGenerator;

private String defaultScope;

/**
* This property lets you set the base package for your mapper interface files.
* <p>
Expand Down Expand Up @@ -311,6 +313,20 @@ public void setNameGenerator(BeanNameGenerator nameGenerator) {
this.nameGenerator = nameGenerator;
}

/**
* Sets the default scope of scanned mappers.
* <p>
* Default is {@code null} (equiv to singleton).
* </p>
*
* @param defaultScope
* the default scope
* @since 2.0.6
*/
public void setDefaultScope(String defaultScope) {
this.defaultScope = defaultScope;
}

/**
* {@inheritDoc}
*/
Expand Down Expand Up @@ -352,6 +368,9 @@ public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
if (StringUtils.hasText(lazyInitialization)) {
scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
}
if (StringUtils.hasText(defaultScope)) {
scanner.setDefaultScope(defaultScope);
}
scanner.registerFilters();
scanner.scan(
StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
Expand Down Expand Up @@ -387,6 +406,7 @@ private void processPropertyPlaceHolders() {
this.sqlSessionFactoryBeanName = updatePropertyValue("sqlSessionFactoryBeanName", values);
this.sqlSessionTemplateBeanName = updatePropertyValue("sqlSessionTemplateBeanName", values);
this.lazyInitialization = updatePropertyValue("lazyInitialization", values);
this.defaultScope = updatePropertyValue("defaultScope", values);
}
this.basePackage = Optional.ofNullable(this.basePackage).map(getEnvironment()::resolvePlaceholders).orElse(null);
this.sqlSessionFactoryBeanName = Optional.ofNullable(this.sqlSessionFactoryBeanName)
Expand All @@ -395,6 +415,7 @@ private void processPropertyPlaceHolders() {
.map(getEnvironment()::resolvePlaceholders).orElse(null);
this.lazyInitialization = Optional.ofNullable(this.lazyInitialization).map(getEnvironment()::resolvePlaceholders)
.orElse(null);
this.defaultScope = Optional.ofNullable(this.defaultScope).map(getEnvironment()::resolvePlaceholders).orElse(null);
}

private Environment getEnvironment() {
Expand Down
11 changes: 10 additions & 1 deletion src/main/resources/org/mybatis/spring/config/mybatis-spring.xsd
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--

Copyright 2010-2019 the original author or authors.
Copyright 2010-2020 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.
Expand Down Expand Up @@ -139,6 +139,15 @@
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="default-scope" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
Specifies the default scope of scanned mappers. (Since 2.0.6)
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Loading