- package com.darren.spring;
-
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
-
- /**
- *
mybatis
- *
- *
- * @author : Darren
- * @date : 2022年07月31日 01:17:52
- **/
- @Configuration
- public class MyBatisConfig {
-
- private static final String BASE_PACKAGE = "com.darren.dao1";
-
- @Bean
- public MyMapperScannerConfigurer myMapperScannerConfigurer(){
- MyMapperScannerConfigurer myMapperScannerConfigurer = new MyMapperScannerConfigurer();
- myMapperScannerConfigurer.setBasePackage(BASE_PACKAGE);
- return myMapperScannerConfigurer;
- }
-
- }
-
- /**
- * 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.
- * 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 com.darren.spring;
-
- 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.core.env.Environment;
- import org.springframework.util.StringUtils;
-
- import java.lang.annotation.Annotation;
- import java.util.Map;
- import java.util.Optional;
-
- 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 substitution 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
- *
- * @see MapperFactoryBean
- */
- public class MyMapperScannerConfigurer
- implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
-
- private String basePackage;
-
- private boolean addToConfig = true;
-
- private String lazyInitialization;
-
- private SqlSessionFactory sqlSessionFactory;
-
- private SqlSessionTemplate sqlSessionTemplate;
-
- private String sqlSessionFactoryBeanName;
-
- private String sqlSessionTemplateBeanName;
-
- private Class extends Annotation> annotationClass;
-
- private Class> markerInterface;
-
- private Class extends MyMapperFactoryBean> mapperFactoryBeanClass;
-
- private ApplicationContext applicationContext;
-
- private String beanName;
-
- private boolean processPropertyPlaceHolders;
-
- private BeanNameGenerator nameGenerator;
-
- /**
- * 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;
- }
-
- /**
- * Same as {@code MapperFactoryBean#setAddToConfig(boolean)}.
- *
- * @param addToConfig
- * a flag that whether add mapper to MyBatis or not
- * @see MapperFactoryBean#setAddToConfig(boolean)
- */
- public void setAddToConfig(boolean addToConfig) {
- this.addToConfig = addToConfig;
- }
-
- /**
- * Set whether enable lazy initialization for mapper bean.
- *
- * Default is {@code false}.
- *
- *
- * @param lazyInitialization
- * Set the @{code true} to enable
- * @since 2.0.2
- */
- public void setLazyInitialization(String lazyInitialization) {
- this.lazyInitialization = lazyInitialization;
- }
-
- /**
- * 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 extends Annotation> annotationClass) {
- this.annotationClass = annotationClass;
- }
-
- /**
- * 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;
- }
-
- /**
- * 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.
- *
- *
- * @deprecated Use {@link #setSqlSessionTemplateBeanName(String)} instead
- *
- * @param sqlSessionTemplate
- * a template of SqlSession
- */
- @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.
- *
- * @since 1.1.0
- *
- * @param sqlSessionTemplateName
- * Bean name of the {@code SqlSessionTemplate}
- */
- public void setSqlSessionTemplateBeanName(String sqlSessionTemplateName) {
- this.sqlSessionTemplateBeanName = sqlSessionTemplateName;
- }
-
- /**
- * 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.
- *
- *
- * @deprecated Use {@link #setSqlSessionFactoryBeanName(String)} instead.
- *
- * @param sqlSessionFactory
- * a factory of SqlSession
- */
- @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.
- *
- * @since 1.1.0
- *
- * @param sqlSessionFactoryName
- * Bean name of the {@code SqlSessionFactory}
- */
- public void setSqlSessionFactoryBeanName(String sqlSessionFactoryName) {
- this.sqlSessionFactoryBeanName = sqlSessionFactoryName;
- }
-
- /**
- * Specifies a flag that whether execute a property placeholder processing or not.
- *
- * The default is {@literal false}. This means that a property placeholder processing does not execute.
- *
- * @since 1.1.1
- *
- * @param processPropertyPlaceHolders
- * a flag that whether execute a property placeholder processing or not
- */
- public void setProcessPropertyPlaceHolders(boolean processPropertyPlaceHolders) {
- this.processPropertyPlaceHolders = processPropertyPlaceHolders;
- }
-
- /**
- * The class of the {@link MapperFactoryBean} to return a mybatis proxy as spring bean.
- *
- * @param mapperFactoryBeanClass
- * The class of the MapperFactoryBean
- * @since 2.0.1
- */
- public void setMapperFactoryBeanClass(Class extends MyMapperFactoryBean> mapperFactoryBeanClass) {
- this.mapperFactoryBeanClass = mapperFactoryBeanClass;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setApplicationContext(ApplicationContext applicationContext) {
- this.applicationContext = applicationContext;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setBeanName(String name) {
- this.beanName = name;
- }
-
- /**
- * 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;
- }
-
- /**
- * {@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();
- }
-
- MyClassPathMapperScanner scanner = new MyClassPathMapperScanner(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.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
- if (StringUtils.hasText(lazyInitialization)) {
- scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
- }
- scanner.registerFilters();
- 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, - false, false);
-
- 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);
- this.lazyInitialization = updatePropertyValue("lazyInitialization", values);
- }
- this.basePackage = Optional.ofNullable(this.basePackage).map(getEnvironment()::resolvePlaceholders).orElse(null);
- this.sqlSessionFactoryBeanName = Optional.ofNullable(this.sqlSessionFactoryBeanName)
- .map(getEnvironment()::resolvePlaceholders).orElse(null);
- this.sqlSessionTemplateBeanName = Optional.ofNullable(this.sqlSessionTemplateBeanName)
- .map(getEnvironment()::resolvePlaceholders).orElse(null);
- this.lazyInitialization = Optional.ofNullable(this.lazyInitialization).map(getEnvironment()::resolvePlaceholders)
- .orElse(null);
- }
-
- private Environment getEnvironment() {
- return this.applicationContext.getEnvironment();
- }
-
- 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;
- }
- }
-
- }
// 实现自己的MyMapperFactoryBean private Class extends MyMapperFactoryBean> mapperFactoryBeanClass;/** * {@inheritDoc} * * @since 1.0.2 */ @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { if (this.processPropertyPlaceHolders) { processPropertyPlaceHolders(); } MyClassPathMapperScanner scanner = new MyClassPathMapperScanner(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.setMapperFactoryBeanClass(this.mapperFactoryBeanClass); if (StringUtils.hasText(lazyInitialization)) { scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization)); } scanner.registerFilters(); scanner.scan( StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS)); } 注: MyMapperScannerConfigurer是实现了BeanDefinitionRegistryPostProcessor,BeanDefinitionRegistryPostProcessor由继承了BeanFactoryPostProcessor,在spring容器启动的时候会调用所有BeanFactoryPostProcessor接口的实现的postProcessBeanDefinitionRegistry方法,MyMapperScannerConfigurer在postProcessBeanDefinitionRegistry方法用来修改BeanDefinition。
- /**
- * Copyright 2010-2019 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 org.mybatis.spring.mapper;
-
- import org.apache.ibatis.session.SqlSessionFactory;
- import org.mybatis.logging.Logger;
- import org.mybatis.logging.LoggerFactory;
- 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 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
- * specified types will be searched (searching for all interfaces will be disabled).
- *
- * This functionality was previously a private class of {@link MapperScannerConfigurer}, but was broken out in version
- * 1.2.0.
- *
- * @author Hunter Presnall
- * @author Eduardo Macarron
- *
- * @see MapperFactoryBean
- * @since 1.2.0
- */
- public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(ClassPathMapperScanner.class);
-
- private boolean addToConfig = true;
-
- private boolean lazyInitialization;
-
- private SqlSessionFactory sqlSessionFactory;
-
- private SqlSessionTemplate sqlSessionTemplate;
-
- private String sqlSessionTemplateBeanName;
-
- private String sqlSessionFactoryBeanName;
-
- private Class extends Annotation> annotationClass;
-
- private Class> markerInterface;
-
- private Class extends MapperFactoryBean> mapperFactoryBeanClass = MapperFactoryBean.class;
-
- public ClassPathMapperScanner(BeanDefinitionRegistry registry) {
- super(registry, false);
- }
-
- public void setAddToConfig(boolean addToConfig) {
- this.addToConfig = addToConfig;
- }
-
- public void setAnnotationClass(Class extends Annotation> annotationClass) {
- this.annotationClass = annotationClass;
- }
-
- /**
- * Set whether enable lazy initialization for mapper bean.
- *
- * Default is {@code false}.
- *
- *
- * @param lazyInitialization
- * Set the @{code true} to enable
- * @since 2.0.2
- */
- public void setLazyInitialization(boolean lazyInitialization) {
- this.lazyInitialization = lazyInitialization;
- }
-
- public void setMarkerInterface(Class> markerInterface) {
- this.markerInterface = markerInterface;
- }
-
- public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
- this.sqlSessionFactory = sqlSessionFactory;
- }
-
- public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
- this.sqlSessionTemplate = sqlSessionTemplate;
- }
-
- public void setSqlSessionTemplateBeanName(String sqlSessionTemplateBeanName) {
- this.sqlSessionTemplateBeanName = sqlSessionTemplateBeanName;
- }
-
- public void setSqlSessionFactoryBeanName(String sqlSessionFactoryBeanName) {
- this.sqlSessionFactoryBeanName = sqlSessionFactoryBeanName;
- }
-
- /**
- * @deprecated Since 2.0.1, Please use the {@link #setMapperFactoryBeanClass(Class)}.
- */
- @Deprecated
- public void setMapperFactoryBean(MapperFactoryBean> mapperFactoryBean) {
- this.mapperFactoryBeanClass = mapperFactoryBean == null ? MapperFactoryBean.class : mapperFactoryBean.getClass();
- }
-
- /**
- * Set the {@code MapperFactoryBean} class.
- *
- * @param mapperFactoryBeanClass
- * the {@code MapperFactoryBean} class
- * @since 2.0.1
- */
- public void setMapperFactoryBeanClass(Class extends MapperFactoryBean> mapperFactoryBeanClass) {
- this.mapperFactoryBeanClass = mapperFactoryBeanClass == null ? MapperFactoryBean.class : mapperFactoryBeanClass;
- }
-
- /**
- * 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()) {
- LOGGER.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();
- String beanClassName = definition.getBeanClassName();
- LOGGER.debug(() -> "Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + beanClassName
- + "' mapperInterface");
-
- // the mapper interface is the original class of the bean
- // but, the actual class of the bean is MapperFactoryBean
- definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59
- definition.setBeanClass(this.mapperFactoryBeanClass);
-
- 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) {
- LOGGER.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) {
- LOGGER.warn(
- () -> "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
- }
- definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
- explicitFactoryUsed = true;
- }
-
- if (!explicitFactoryUsed) {
- LOGGER.debug(() -> "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
- definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
- }
- definition.setLazyInit(lazyInitialization);
- }
- }
-
- /**
- * {@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 {
- LOGGER.warn(() -> "Skipping MapperFactoryBean with name '" + beanName + "' and '"
- + beanDefinition.getBeanClassName() + "' mapperInterface" + ". Bean already defined with the same name!");
- return false;
- }
- }
-
- }
/**
* 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 SetdoScan(String... basePackages) {
SetbeanDefinitions = super.doScan(basePackages); if (beanDefinitions.isEmpty()) {
LOGGER.warn(() -> "No MyBatis mapper was found in '" + Arrays.toString(basePackages)
+ "' package. Please check your configuration.");
} else {
processBeanDefinitions(beanDefinitions);
}return beanDefinitions;
}
调用父类ClassPathBeanDefinitionScanner的doScan方法,返回所有扫描到的BeanDefinition对象
注册:其实就是添加到BeanFactory(默认实现:DefaultListableBeanFactory)里面的Map
beanDefinitionMap中
- /**
- * Perform a scan within the specified base packages.
- * @param basePackages the packages to check for annotated classes
- * @return number of beans registered
- */
- public int scan(String... basePackages) {
- int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
-
- doScan(basePackages);
-
- // Register annotation config processors, if necessary.
- if (this.includeAnnotationConfig) {
- AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
- }
-
- return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
- }
doScan是真正扫描的地方,并注册的地方,传入的basePackages就是MyBatisConfig传入的要扫描的包路径
// 实现自己的MyMapperFactoryBean private Class extends MyMapperFactoryBean> mapperFactoryBeanClass = MyMapperFactoryBean.class;
private void processBeanDefinitions(Set
beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) {// 将拿到的BeanDefinition转换为普通的BeanDefinition
definition = (GenericBeanDefinition) holder.getBeanDefinition();// 拿到bean的名称
String beanClassName = definition.getBeanClassName();
LOGGER.debug(() -> "Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + beanClassName
+ "' mapperInterface");// the mapper interface is the original class of the bean
// but, the actual class of the bean is MapperFactoryBean
// 构造器参数中传入mapper接口的名称definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59
// 设置自己的实现的MyMapperFactoryBean
definition.setBeanClass(this.mapperFactoryBeanClass);// 添加一个addToConfig的参数
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) {
LOGGER.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) {
LOGGER.warn(
() -> "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
explicitFactoryUsed = true;
}if (!explicitFactoryUsed) {
LOGGER.debug(() -> "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");// 设置自动装配的模式
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}// 设置懒加载
definition.setLazyInit(lazyInitialization);
}
}
- /**
- * Copyright 2010-2019 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 com.darren.spring;
-
- import static org.springframework.util.Assert.notNull;
-
- import org.apache.ibatis.executor.ErrorContext;
- import org.apache.ibatis.io.Resources;
- import org.apache.ibatis.session.Configuration;
- import org.apache.ibatis.session.SqlSession;
- import org.apache.ibatis.session.SqlSessionFactory;
- import org.apache.ibatis.session.SqlSessionFactoryBuilder;
- import org.mybatis.spring.SqlSessionTemplate;
- import org.mybatis.spring.support.SqlSessionDaoSupport;
- import org.springframework.beans.factory.FactoryBean;
-
- import java.io.IOException;
- import java.io.InputStream;
-
- /**
- * BeanFactory that enables injection of MyBatis mapper interfaces. It can be set up with a SqlSessionFactory or a
- * pre-configured SqlSessionTemplate.
- *
- * Sample configuration:
- *
- *
- * {@code
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- * }
- *
- *
- * Note that this factory can only inject interfaces, not concrete classes.
- *
- * @author Eduardo Macarron
- *
- * @see SqlSessionTemplate
- */
- public class MyMapperFactoryBean
implements FactoryBean { -
- private SqlSessionFactory sqlSessionFactory;
-
- private Class
mapperInterface; -
- private boolean addToConfig = true;
-
- public MyMapperFactoryBean() {
- // intentionally empty
- }
-
- public MyMapperFactoryBean(Class
mapperInterface) { - this.mapperInterface = mapperInterface;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public T getObject() throws Exception {
- this.getSqlSessionFactory();
- SqlSession sqlSession = sqlSessionFactory.openSession();
- return sqlSession.getMapper(this.mapperInterface);
- }
-
- private void getSqlSessionFactory(){
- // 根据全局配置文件创建出SqlSessionFactory
- // SqlSessionFactory:负责创建SqlSession对象的工厂
- // SqlSession:表示跟数据库建议的一次会话
- String resource = "mybatis-config.xml";
- InputStream inputStream = null;
- try {
- inputStream = Resources.getResourceAsStream(resource);
- } catch (IOException e) {
- e.printStackTrace();
- }
- sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Class
getObjectType() { - return this.mapperInterface;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean isSingleton() {
- return true;
- }
-
- // ------------- mutators --------------
-
- /**
- * Sets the mapper interface of the MyBatis mapper
- *
- * @param mapperInterface
- * class of the interface
- */
- public void setMapperInterface(Class
mapperInterface) { - this.mapperInterface = mapperInterface;
- }
-
- /**
- * Return the mapper interface of the MyBatis mapper
- *
- * @return class of the interface
- */
- public Class
getMapperInterface() { - return mapperInterface;
- }
-
- /**
- * If addToConfig is false the mapper will not be added to MyBatis. This means it must have been included in
- * mybatis-config.xml.
- *
- * If it is true, the mapper will be added to MyBatis in the case it is not already registered.
- *
- * By default addToConfig is true.
- *
- * @param addToConfig
- * a flag that whether add mapper to MyBatis or not
- */
- public void setAddToConfig(boolean addToConfig) {
- this.addToConfig = addToConfig;
- }
-
- /**
- * Return the flag for addition into MyBatis config.
- *
- * @return true if the mapper will be added to MyBatis in the case it is not already registered.
- */
- public boolean isAddToConfig() {
- return addToConfig;
- }
- }
/**
* {@inheritDoc}
*/
@Override
public T getObject() throws Exception {// 初始化SqlSessionFactory
this.getSqlSessionFactory();// 打开一个SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();// 返回mapper接口的代理对象
return sqlSession.getMapper(this.mapperInterface);
}
private void getSqlSessionFactory(){
// 根据全局配置文件创建出SqlSessionFactory
// SqlSessionFactory:负责创建SqlSession对象的工厂
// SqlSession:表示跟数据库建议的一次会话
String resource = "mybatis-config.xml";
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(resource);
} catch (IOException e) {
e.printStackTrace();
}
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
- package com.darren;
-
- import com.darren.bean.Emp;
- import com.darren.dao.EmpDao;
- import com.darren.dao1.EmpDao1;
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.test.context.ContextConfiguration;
- import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
-
- import java.util.List;
-
- /**
- *
mybatis
- *
- *
- * @author : Darren
- * @date : 2022年07月24日 18:30:32
- **/
- @ContextConfiguration(locations = {"classpath:spring.xml"})
- @RunWith(SpringJUnit4ClassRunner.class)
- public class MyBatisSpringTest {
-
- @Autowired
- private EmpDao dao;
- @Autowired
- private EmpDao1 dao1;
-
- @Test
- public void test01(){
- List
empByEmpno = dao.selectAll(); - empByEmpno.stream().forEach(System.out::println);
-
- List
empByEmpno1 = dao1.selectAll(); - empByEmpno1.stream().forEach(System.out::println);
- }
-
- }
-
// 没有修改过的
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7203c7ff] was not registered for synchronization because synchronization is not active
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@59252cb6] will not be managed by Spring
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7203c7ff]
Emp{empno=7369, ename='Darren', job='CEO', mgr=1000000, hiredate=Wed Jun 10 08:00:00 CST 2015, sal=1.0E7, common=null, deptno=0}
Emp{empno=7379, ename='Darren1', job='CEO', mgr=1000000, hiredate=Wed Jun 10 08:00:00 CST 2015, sal=1.0E7, common=null, deptno=0}
// 自己修改的(配置文件开启了logImpl,所以打了sql日志)
Opening JDBC Connection
Created connection 1033348658.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@3d97a632]
==> Preparing: select * from emp
==> Parameters:
<== Columns: empno, ename, job, mgr, hiredate, sal, common, deptno, create_time, update_time
<== Row: 7369, Darren, CEO, 1000000, 2015-06-10 00:00:00, 10000000.00, null, 0, 2022-07-24 09:38:43, 2022-07-24 09:38:43
<== Row: 7379, Darren1, CEO, 1000000, 2015-06-10 00:00:00, 10000000.00, null, 0, 2022-07-24 17:11:34, 2022-07-24 17:11:34
<== Total: 2
Emp{empno=7369, ename='Darren', job='CEO', mgr=1000000, hiredate=Wed Jun 10 08:00:00 CST 2015, sal=1.0E7, common=null, deptno=0}
Emp{empno=7379, ename='Darren1', job='CEO', mgr=1000000, hiredate=Wed Jun 10 08:00:00 CST 2015, sal=1.0E7, common=null, deptno=0}