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

app.myoss.cloud.mybatis.spring.mapper.MapperScannerConfigurer 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 static org.springframework.util.Assert.notNull;

import java.lang.annotation.Annotation;
import java.util.Map;

import org.springframework.beans.PropertyValue;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertyResourceConfigurer;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.util.StringUtils;

import app.myoss.cloud.mybatis.mapper.register.MapperInterfaceRegister;
import app.myoss.cloud.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration.AutoConfiguredMapperScannerRegistrar2;
import lombok.Data;

/**
 * 配置扫描Class Path目录Mapper Interface,实现
 * {@link org.mybatis.spring.mapper.MapperScannerConfigurer} 类似的功能,但是用的是自己的
 * {@link ClassPathMapperScanner}
 *
 * @author Jerry.Chen
 * @since 2018年5月20日 下午12:47:18
 * @see ClassPathMapperScanner
 * @see MapperFactoryBean
 * @see AutoConfiguredMapperScannerRegistrar2
 * @see org.mybatis.spring.mapper.MapperScannerConfigurer
 */
@Data
public class MapperScannerConfigurer
        implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
    /**
     * basePackage base package name
     * 

* This property lets you set the base package for your mapper interface * files. *

* You can set more than one package by using a semicolon or comma as a * separator. *

* Mappers will be searched for recursively starting in the specified * package(s). */ private String basePackage; /** * Same as {@link MapperFactoryBean#setAddToConfig(boolean)} */ private boolean addToConfig = true; /** * Bean name of the {@code SqlSessionFactory} *

* Specifies which {@code SqlSessionFactory} to use in the case that there * is more than one in the spring context. Usually this is only needed when * you have more than one datasource. *

* Note bean names are used, not bean references. This is because the * scanner loads early during the start process and it is too early to build * mybatis object instances. */ private String sqlSessionFactoryBeanName; /** * Bean name of the {@code SqlSessionTemplate} *

* Specifies which {@code SqlSessionTemplate} to use in the case that there * is more than one in the spring context. Usually this is only needed when * you have more than one datasource. *

* Note bean names are used, not bean references. This is because the * scanner loads early during the start process and it is too early to build * mybatis object instances. */ private String sqlSessionTemplateBeanName; /** * annotation class *

* This property specifies the annotation that the scanner will search for. *

* The scanner will register all interfaces in the base package that also * have the specified annotation. *

* Note this can be combined with markerInterface. */ private Class annotationClass; /** * parent class *

* This property specifies the parent that the scanner will search for. *

* The scanner will register all interfaces in the base package that also * have the specified interface class as a parent. *

* Note this can be combined with annotationClass. */ private Class markerInterface; /** * BeanFactory that enables injection of MyBatis mapper interfaces */ private MapperFactoryBean mapperFactoryBean; /** * 通用 Mapper 接口注册器 */ private MapperInterfaceRegister mapperInterfaceRegister; /** * Bean name of the {@code MapperInterfaceRegister} */ private String mapperInterfaceRegisterBeanName; private ApplicationContext applicationContext; private String beanName; private boolean processPropertyPlaceHolders; /** * the beanNameGenerator BeanNameGenerator that has been configured *

* Gets beanNameGenerator to be used while running the scanner. */ private BeanNameGenerator nameGenerator; @Override public void setApplicationContext(ApplicationContext applicationContext) { this.applicationContext = applicationContext; } @Override public void setBeanName(String name) { this.beanName = name; } @Override public void afterPropertiesSet() throws Exception { notNull(this.basePackage, "Property 'basePackage' is required"); } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { // left intentionally blank } @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { if (this.processPropertyPlaceHolders) { processPropertyPlaceHolders(); } ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry); scanner.setAddToConfig(this.addToConfig); scanner.setAnnotationClass(this.annotationClass); scanner.setMarkerInterface(this.markerInterface); scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName); scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName); if (this.mapperFactoryBean != null) { scanner.setMapperFactoryBean(this.mapperFactoryBean); } if (this.mapperInterfaceRegister != null) { scanner.setMapperInterfaceRegister(this.mapperInterfaceRegister); } if (!StringUtils.isEmpty(this.mapperInterfaceRegisterBeanName)) { scanner.setMapperInterfaceRegisterBeanName(this.mapperInterfaceRegisterBeanName); } scanner.setResourceLoader(this.applicationContext); scanner.setBeanNameGenerator(this.nameGenerator); scanner.registerFilters(); String[] basePackages = StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); scanner.scan(basePackages); } /** * BeanDefinitionRegistries are called early in application startup, before * BeanFactoryPostProcessors. This means that PropertyResourceConfigurers * will not have been loaded and any property substitution of this class' * properties will fail. To avoid this, find any PropertyResourceConfigurers * defined in the context and run them on this class' bean definition. Then * update the values. */ private void processPropertyPlaceHolders() { Map prcs = applicationContext .getBeansOfType(PropertyResourceConfigurer.class); if (!prcs.isEmpty() && applicationContext instanceof ConfigurableApplicationContext) { BeanDefinition mapperScannerBean = ((ConfigurableApplicationContext) applicationContext).getBeanFactory() .getBeanDefinition(beanName); // PropertyResourceConfigurer does not expose any methods to explicitly perform // property placeholder substitution. Instead, create a BeanFactory that just // contains this mapper scanner and post process the factory. DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); factory.registerBeanDefinition(beanName, mapperScannerBean); for (PropertyResourceConfigurer prc : prcs.values()) { prc.postProcessBeanFactory(factory); } PropertyValues values = mapperScannerBean.getPropertyValues(); this.basePackage = updatePropertyValue("basePackage", values); this.sqlSessionFactoryBeanName = updatePropertyValue("sqlSessionFactoryBeanName", values); this.sqlSessionTemplateBeanName = updatePropertyValue("sqlSessionTemplateBeanName", values); } } private String updatePropertyValue(String propertyName, PropertyValues values) { PropertyValue property = values.getPropertyValue(propertyName); if (property == null) { return null; } Object value = property.getValue(); if (value == null) { return null; } else if (value instanceof String) { return value.toString(); } else if (value instanceof TypedStringValue) { return ((TypedStringValue) value).getValue(); } else { return null; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy