All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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 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