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

querymethods.MapperScannerConfigurer Maven / Gradle / Ivy

There is a newer version: 0.1.4-RELEASE
Show newest version
/**
 *    Copyright 2010-2016 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.
 *    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 querymethods;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
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 tk.mybatis.mapper.common.Marker;
import tk.mybatis.mapper.mapperhelper.MapperHelper;
import tk.mybatis.spring.mapper.ClassPathMapperScanner;

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

import static org.springframework.util.Assert.notNull;

/**
 * BeanDefinitionRegistryPostProcessor that searches recursively starting from a base package for
 * interfaces and registers them as {@code MapperFactoryBean}. Note that only interfaces with at
 * least one method will be registered; concrete classes will be ignored.
 * 

* This class was a {code BeanFactoryPostProcessor} until 1.0.1 version. It changed to * {@code BeanDefinitionRegistryPostProcessor} in 1.0.2. See https://jira.springsource.org/browse/SPR-8269 * for the details. *

* The {@code basePackage} property can contain more than one package name, separated by either * commas or semicolons. *

* This class supports filtering the mappers created by either specifying a marker interface or an * annotation. The {@code annotationClass} property specifies an annotation to search for. The * {@code markerInterface} property specifies a parent interface to search for. If both properties * are specified, mappers are added for interfaces that match either criteria. By default, * these two properties are null, so all interfaces in the given {@code basePackage} are added as * mappers. *

* This configurer enables autowire for all the beans that it creates so that they are * automatically autowired with the proper {@code SqlSessionFactory} or {@code SqlSessionTemplate}. * If there is more than one {@code SqlSessionFactory} in the application, however, autowiring * cannot be used. In this case you must explicitly specify either an {@code SqlSessionFactory} or * an {@code SqlSessionTemplate} to use via the bean name properties. Bean names are used * rather than actual objects because Spring does not initialize property placeholders until after * this class is processed. *

* Passing in an actual object which may require placeholders (i.e. DB user password) will fail. * Using bean names defers actual object creation until later in the startup * process, after all placeholder substituation is completed. However, note that this configurer * does support property placeholders of its own properties. The basePackage * and bean name properties all support ${property} style substitution. *

* Configuration sample: *

*

*

 * {@code
 * 
 * 
 * 
 * 
 * 
 * }
 * 
* * @author Hunter Presnall * @author Eduardo Macarron * @author liuzh * @see tk.mybatis.spring.mapper.MapperFactoryBean * @see ClassPathMapperScanner */ public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware { private String basePackage; private boolean addToConfig = true; private SqlSessionFactory sqlSessionFactory; private SqlSessionTemplate sqlSessionTemplate; private String sqlSessionFactoryBeanName; private String sqlSessionTemplateBeanName; private Class annotationClass; private Class markerInterface; private ApplicationContext applicationContext; private String beanName; private boolean processPropertyPlaceHolders; private BeanNameGenerator nameGenerator; private MapperHelper mapperHelper = new MapperHelper(); public MapperHelper getMapperHelper() { return mapperHelper; } public void setMapperHelper(MapperHelper mapperHelper) { this.mapperHelper = mapperHelper; } /** * {@inheritDoc} */ @Override public void afterPropertiesSet() throws Exception { notNull(this.basePackage, "Property 'basePackage' is required"); } /** * {@inheritDoc} */ @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { // left intentionally blank } /** * {@inheritDoc} * * @since 1.0.2 */ @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.setSqlSessionFactory(this.sqlSessionFactory); scanner.setSqlSessionTemplate(this.sqlSessionTemplate); scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName); scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName); scanner.setResourceLoader(this.applicationContext); scanner.setBeanNameGenerator(this.nameGenerator); scanner.registerFilters(); //设置通用 Mapper scanner.setMapperHelper(this.mapperHelper); scanner.setMapperFactoryBean(new QueryMethodsMapperFactoryBean<>()); scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS)); } /* * 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; } } /** * Gets beanNameGenerator to be used while running the scanner. * * @return the beanNameGenerator BeanNameGenerator that has been configured * @since 1.2.0 */ public BeanNameGenerator getNameGenerator() { return nameGenerator; } /** * Sets beanNameGenerator to be used while running the scanner. * * @param nameGenerator the beanNameGenerator to set * @since 1.2.0 */ public void setNameGenerator(BeanNameGenerator nameGenerator) { this.nameGenerator = nameGenerator; } /** * Same as {@code MapperFactoryBean#setAddToConfig(boolean)}. * * @param addToConfig * @see MapperFactoryBean#setAddToConfig(boolean) */ public void setAddToConfig(boolean addToConfig) { this.addToConfig = addToConfig; } /** * 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. * * @param annotationClass annotation class */ public void setAnnotationClass(Class annotationClass) { this.annotationClass = annotationClass; } /** * {@inheritDoc} */ @Override public void setApplicationContext(ApplicationContext applicationContext) { this.applicationContext = applicationContext; } /** * 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). * * @param basePackage base package name */ public void setBasePackage(String basePackage) { this.basePackage = basePackage; } /** * {@inheritDoc} */ @Override public void setBeanName(String name) { this.beanName = name; } /** * 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. * * @param superClass parent class */ public void setMarkerInterface(Class superClass) { this.markerInterface = superClass; if (Marker.class.isAssignableFrom(superClass)) { mapperHelper.registerMapper(superClass); } } /** * @param processPropertyPlaceHolders * @since 1.1.1 */ public void setProcessPropertyPlaceHolders(boolean processPropertyPlaceHolders) { this.processPropertyPlaceHolders = processPropertyPlaceHolders; } /** * 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. *

* * @param sqlSessionFactory * @deprecated Use {@link #setSqlSessionFactoryBeanName(String)} instead. */ @Deprecated public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) { this.sqlSessionFactory = 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. * * @param sqlSessionFactoryName Bean name of the {@code SqlSessionFactory} * @since 1.1.0 */ public void setSqlSessionFactoryBeanName(String sqlSessionFactoryName) { this.sqlSessionFactoryBeanName = sqlSessionFactoryName; } /** * 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. *

* * @param sqlSessionTemplate * @deprecated Use {@link #setSqlSessionTemplateBeanName(String)} instead */ @Deprecated public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) { this.sqlSessionTemplate = 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. * * @param sqlSessionTemplateName Bean name of the {@code SqlSessionTemplate} * @since 1.1.0 */ public void setSqlSessionTemplateBeanName(String sqlSessionTemplateName) { this.sqlSessionTemplateBeanName = sqlSessionTemplateName; } /** * 属性注入 * * @param properties */ public void setProperties(Properties properties) { mapperHelper.setProperties(properties); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy