
app.myoss.cloud.mybatis.spring.mapper.ClassPathMapperScanner Maven / Gradle / Ivy
/*
* Copyright 2018-2018 https://github.com/myoss
*
* 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.
*
*/
package app.myoss.cloud.mybatis.spring.mapper;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Set;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
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.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.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.util.StringUtils;
import app.myoss.cloud.mybatis.mapper.register.MapperInterfaceRegister;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
/**
* 扫描Class Path目录Mapper Interface
*
* @author Jerry.Chen
* @since 2018年4月24日 下午6:18:05
*/
@Slf4j
@Setter
public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
private boolean addToConfig = true;
private SqlSessionFactory sqlSessionFactory;
private SqlSessionTemplate sqlSessionTemplate;
private String sqlSessionTemplateBeanName;
private String sqlSessionFactoryBeanName;
private Class extends Annotation> annotationClass;
private Class> markerInterface;
/**
* BeanFactory that enables injection of MyBatis mapper interfaces
*/
private MapperFactoryBean> mapperFactoryBean = new MapperFactoryBean<>();
/**
* 通用 Mapper 接口注册器
*/
private MapperInterfaceRegister mapperInterfaceRegister;
/**
* Bean name of the {@code MapperInterfaceRegister}
*/
private String mapperInterfaceRegisterBeanName;
/**
* 初始化 扫描Class Path目录Mapper Interface
*
* @param registry Bean定义注册器
*/
public ClassPathMapperScanner(BeanDefinitionRegistry registry) {
super(registry, false);
}
/**
* 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
*/
public void registerFilters() {
boolean acceptAllInterfaces = true;
// if specified, use the given annotation and / or marker interface
if (this.annotationClass != null) {
addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));
acceptAllInterfaces = false;
}
// override AssignableTypeFilter to ignore matches on the actual marker interface
if (this.markerInterface != null) {
addIncludeFilter(new AssignableTypeFilter(this.markerInterface) {
@Override
protected boolean matchClassName(String className) {
return false;
}
});
acceptAllInterfaces = false;
}
if (acceptAllInterfaces) {
// default include filter that accepts all classes
addIncludeFilter((metadataReader, metadataReaderFactory) -> true);
}
// exclude package-info.java
addExcludeFilter((metadataReader, metadataReaderFactory) -> {
String className = metadataReader.getClassMetadata().getClassName();
return className.endsWith("package-info");
});
}
/**
* Calls the parent search that will search and register all the candidates.
* Then the registered objects are post processed to set them as
* MapperFactoryBeans
*/
@Override
public Set doScan(String... basePackages) {
Set beanDefinitions = super.doScan(basePackages);
if (beanDefinitions.isEmpty()) {
log.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages)
+ "' package. Please check your configuration.");
} else {
processBeanDefinitions(beanDefinitions);
}
return beanDefinitions;
}
private void processBeanDefinitions(Set beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) {
definition = (GenericBeanDefinition) holder.getBeanDefinition();
if (log.isDebugEnabled()) {
log.debug("Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '"
+ definition.getBeanClassName() + "' mapperInterface");
}
// the mapper interface is the original class of the bean
// but, the actual class of the bean is MapperFactoryBean
definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName());
definition.setBeanClass(this.mapperFactoryBean.getClass());
definition.getPropertyValues().add("addToConfig", this.addToConfig);
boolean explicitFactoryUsed = false;
if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
definition.getPropertyValues().add("sqlSessionFactory",
new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionFactory != null) {
definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
explicitFactoryUsed = true;
}
if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
if (explicitFactoryUsed) {
log.warn(
"Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate",
new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionTemplate != null) {
if (explicitFactoryUsed) {
log.warn(
"Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
explicitFactoryUsed = true;
}
if (!explicitFactoryUsed) {
if (log.isDebugEnabled()) {
log.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName()
+ "'.");
}
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
explicitFactoryUsed = false;
if (StringUtils.hasText(this.mapperInterfaceRegisterBeanName)) {
definition.getPropertyValues().add("mapperInterfaceRegister",
new RuntimeBeanReference(this.mapperInterfaceRegisterBeanName));
explicitFactoryUsed = true;
}
if (this.mapperInterfaceRegister != null) {
if (explicitFactoryUsed) {
log.warn(
"Cannot use both: mapperInterfaceRegisterBeanName and mapperInterfaceRegister together. mapperInterfaceRegister is ignored.");
} else {
definition.getPropertyValues().add("mapperInterfaceRegister", this.mapperInterfaceRegister);
}
}
if (this.mapperInterfaceRegister == null && StringUtils.isEmpty(this.mapperInterfaceRegisterBeanName)) {
definition.getPropertyValues().add("mapperInterfaceRegister",
new RuntimeBeanReference("mapperInterfaceRegister"));
}
}
}
/**
* {@inheritDoc}
*/
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
}
/**
* {@inheritDoc}
*/
@Override
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) {
if (super.checkCandidate(beanName, beanDefinition)) {
return true;
} else {
log.warn("Skipping MapperFactoryBean with name '" + beanName + "' and '" + beanDefinition.getBeanClassName()
+ "' mapperInterface" + ". Bean already defined with the same name!");
return false;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy