[source code analysis] the principle of springboot automatic configuration and how mybatis is automatically configured

Time:2021-12-23

Spring boot auto configuration principle

1. Set up springboot

The parent project that all springboot needs to introduce: version control

<parent>
    <artifactId>spring-boot-starter-parent</artifactId>
    <groupId>org.springframework.boot</groupId>
    <version>2.1.11.RELEASE</version>
</parent>

Its parent project is

<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.11.RELEASE</version>

This project is the version control center of springboot![source code analysis] the principle of springboot automatic configuration and how mybatis is automatically configured)

Then we need to introduce the initiator of the module we need to use. The naming standard officially provided by spring is spring boot starter XXX, such as

Spring-boot-starter-web

It is not officially provided by spring and is named XXX spring boot starter, such as mybatis spring boot starter

The so-called launcher is essentially an empty jar project, which is only used to introduce dependencies.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Finally, we need to write a startup class

package com.sunning;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class HelloSpringBootApplication {


    public static void main(String[] args) {


        SpringApplication.run(HelloSpringBootApplication.class,args);
    }
}

2. Automatic configuration principle

@SpringBootApplication

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
      @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })

Equal to the above three annotations

@SpringBootConfiguration

Click to see the @ configuration annotation, which declares that it is a spring configuration class

@EnableAutoConfiguration

The most critical annotation for springboot startup

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

   String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

   /**
    * Exclude specific auto-configuration classes such that they will never be applied.
    * @return the classes to exclude
    */
   Class<?>[] exclude() default {};

   /**
    * Exclude specific auto-configuration class names such that they will never be
    * applied.
    * @return the class names to exclude
    * @since 1.3.0
    */
   String[] excludeName() default {};

}

[source code analysis] the principle of springboot automatic configuration and how mybatis is automatically configured

Implements the importselector interface

public interface ImportSelector {

   /**
    * Select and return the names of which class(es) should be imported based on
    * the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
    */
   String[] selectImports(AnnotationMetadata importingClassMetadata);

}

The interface returns a string [] array representing the full class name of the class to be registered with the container

[source code analysis] the principle of springboot automatic configuration and how mybatis is automatically configured

[source code analysis] the principle of springboot automatic configuration and how mybatis is automatically configured

List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
      getBeanClassLoader());

Springfactoryesloader is a tool class provided by spring. The first parameter is a class object. The key to be read is the full class name of the class object. The second parameter is the classloader object. Decide where to find this file and read the classpath: meta-inf / spring Factories file

[source code analysis] the principle of springboot automatic configuration and how mybatis is automatically configured
Naturally, there is no automatic configuration class. The automatic configuration class of mybatis is provided by mybatis

Read these values and import them into the core container.

At this point, various autoconfiguration classes under the spring autoconfiguration package are registered in the core container
[source code analysis] the principle of springboot automatic configuration and how mybatis is automatically configured

Springboot will register the autoconfiguration classes under this package to the core container at startup, and these autoconfiguration classes are simply @ configuration classes with effective conditions.

[source code analysis] the principle of springboot automatic configuration and how mybatis is automatically configured

@The conditionalonclass annotation indicates whether some classes exist in the current class path before they take effect.

@Conditionalonproperty takes effect only when the corresponding configuration fields are met.

@Conditionalonmissingbean takes effect only when there is no bean in the container. At this time, if we configure it, spring boot will not be automatically configured for us.

There are many similar. The configuration class will not take effect until these conditions are met at the same time.

You can see that the so-called springboot automatic configuration is the introduction of some configuration classes, and these configuration classes only take effect under certain conditions. The principle of springboot is that the default is greater than the configuration, so when we need to change the default configuration, the source code of these automatic configurations is a very important reference. Typical methods to modify the default configuration include: configuring in the configuration file, registering a specific bean in the container, injecting some classes named xxxconfigurer (such as those that implement the webmvcconfigurer interface), and so on.

Logging. Can be set in the configuration file level. org. springframework. boot. Autoconfigure = debug to view the effectiveness of automatic configuration

[source code analysis] the principle of springboot automatic configuration and how mybatis is automatically configured

[source code analysis] the principle of springboot automatic configuration and how mybatis is automatically configured

@AutoConfigurationPackage
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {

}

It can be seen from the code that it is just an @ import annotation. As mentioned earlier, import can be followed by the importselector interface to register the string array returned by the selectimports method into the core container. Here is another interface supported by import, importbeandefinitionregistrar.

public interface ImportBeanDefinitionRegistrar {

   /**
    * Register bean definitions as necessary based on the given annotation metadata of
    * the importing {@code @Configuration} class.
    * <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
    * registered here, due to lifecycle constraints related to {@code @Configuration}
    * class processing.
    * @param importingClassMetadata annotation metadata of the importing class
    * @param registry current bean definition registry
    */
   void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);

}

This interface uses registry to register components in the core container.

Next, we focus on what @ import (autoconfigurationpackages. Registrar. Class) does.

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

   @Override
   public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
      register(registry, new PackageImport(metadata).getPackageName());
   }

   @Override
   public Set<Object> determineImports(AnnotationMetadata metadata) {
      return Collections.singleton(new PackageImport(metadata));
   }

}

register(registry, new PackageImport(metadata).getPackageName());

new PackageImport(metadata). getPackageName()。 It is equivalent to passing in the package name of the annotated class. Here is the package of hellospprinbootapplication: com sunning。 Next, look at the logic of the register method

public static void register(BeanDefinitionRegistry registry, String... packageNames) {
   if (registry.containsBeanDefinition(BEAN)) {
      BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
      ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues();
      constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames));
   }
   else {
      GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
      beanDefinition.setBeanClass(BasePackages.class);
      beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);
      beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
      registry.registerBeanDefinition(BEAN, beanDefinition);
   }
}

This method is to judge whether the core container has registered bean (the value of this constant). If so, add packagenames to the constructor in the bean definition. Otherwise, register a bean, named bean, which is of basepackages type, and add packagenames to its constructor.

Therefore, it can be seen that the function of this annotation is to register a bean of basepackages type in the core container and set its construction method to the package name of the class annotated with this annotation. The purpose of registering this bean is also to prepare for subsequent automatic configuration. For example, this bean is used in the automatic configuration of mybatis to determine which packages to scan @ mapper annotations.

@ComponentScan

Scan the package, and the configurationclasspostprocessor implements this annotation. If you are interested, you can learn about the beanfactoryprocessor interface in the spring life cycle.

3. Take the integration of spring boot and mybatis as an example

Dependency introduction

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.1</version>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

Spring does not provide an initiator for mybatis, and naturally there is no automatic configuration class. The automatic configuration class of mybatis is provided by mybatis!

[source code analysis] the principle of springboot automatic configuration and how mybatis is automatically configured
Automatic configuration package provided by mybatis. As can be seen from the above principle, in order for the automatic configuration class to be loaded by the container, it needs to be in the classpath: meta-inf / spring Factories indicates the autoconfiguration class that needs to be loaded

[source code analysis] the principle of springboot automatic configuration and how mybatis is automatically configured

You can see that mybatis provides these automatic configuration classes.

MybatisAutoConfiguration

Let’s focus on what configuration this class provides us
[source code analysis] the principle of springboot automatic configuration and how mybatis is automatically configured

You can see the effective conditions. For example, when you need to introduce a dependency related to mybatis, for example, when there is only one datasource in the core container, it will not take effect until the datasource is automatically configured. And the configuration class @ enableconfigurationproperties (mybatisproperties. Class) is opened

Construction method
public MybatisAutoConfiguration(MybatisProperties properties, ObjectProvider<Interceptor[]> interceptorsProvider,
    ObjectProvider<TypeHandler[]> typeHandlersProvider, ObjectProvider<LanguageDriver[]> languageDriversProvider,
    ResourceLoader resourceLoader, ObjectProvider<DatabaseIdProvider> databaseIdProvider,
    ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider) {
  this.properties = properties;
  this.interceptors = interceptorsProvider.getIfAvailable();
  this.typeHandlers = typeHandlersProvider.getIfAvailable();
  this.languageDrivers = languageDriversProvider.getIfAvailable();
  this.resourceLoader = resourceLoader;
  this.databaseIdProvider = databaseIdProvider.getIfAvailable();
  this.configurationCustomizers = configurationCustomizersProvider.getIfAvailable();
}

Therefore, when the object is instantiated, it will be injected into a series of beans, such as the mybatisproperties object.

Creation of sqlsessionfactory

Inject the sqlsessionfactory object into the container, Get datasource from container (when we introduce spring-boot-starter-jdbc, we automatically configure) as a parameter. Create a SqlSessionFactoryBean object. This object is a factory used to produce SqlSessionFactory. We call a series of set methods of factory objects, and finally call getObject method to get SqlSessionFactory objects. The middle procedure is to generate Config needed by SqlSessionFactory. The process of the configuration object (replacing the main configuration file of mybatis).

@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
  SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
  factory.setDataSource(dataSource);
  factory.setVfs(SpringBootVFS.class);
  if (StringUtils.hasText(this.properties.getConfigLocation())) {
    factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
  }
  applyConfiguration(factory);
  if (this.properties.getConfigurationProperties() != null) {
    factory.setConfigurationProperties(this.properties.getConfigurationProperties());
  }
  if (!ObjectUtils.isEmpty(this.interceptors)) {
    factory.setPlugins(this.interceptors);
  }
  if (this.databaseIdProvider != null) {
    factory.setDatabaseIdProvider(this.databaseIdProvider);
  }
  if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
    factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
  }
  if (this.properties.getTypeAliasesSuperType() != null) {
    factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());
  }
  if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
    factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
  }
  if (!ObjectUtils.isEmpty(this.typeHandlers)) {
    factory.setTypeHandlers(this.typeHandlers);
  }
  if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
    factory.setMapperLocations(this.properties.resolveMapperLocations());
  }
  Set<String> factoryPropertyNames = Stream
      .of(new BeanWrapperImpl(SqlSessionFactoryBean.class).getPropertyDescriptors()).map(PropertyDescriptor::getName)
      .collect(Collectors.toSet());
  Class<? extends LanguageDriver> defaultLanguageDriver = this.properties.getDefaultScriptingLanguageDriver();
  if (factoryPropertyNames.contains("scriptingLanguageDrivers") && !ObjectUtils.isEmpty(this.languageDrivers)) {
    // Need to mybatis-spring 2.0.2+
    factory.setScriptingLanguageDrivers(this.languageDrivers);
    if (defaultLanguageDriver == null && this.languageDrivers.length == 1) {
      defaultLanguageDriver = this.languageDrivers[0].getClass();
    }
  }
  if (factoryPropertyNames.contains("defaultScriptingLanguageDriver")) {
    // Need to mybatis-spring 2.0.2+
    factory.setDefaultScriptingLanguageDriver(defaultLanguageDriver);
  }

  return factory.getObject();
}

You can focus on the applyconfiguration method

private void applyConfiguration(SqlSessionFactoryBean factory) {
  Configuration configuration = this.properties.getConfiguration();
  if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) {
    configuration = new Configuration();
  }
  if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) {
    for (ConfigurationCustomizer customizer : this.configurationCustomizers) {
      customizer.customize(configuration);
    }
  }
  factory.setConfiguration(configuration);
}

This is the example of spring boot configuration modification by xxxcustomizer mentioned earlier. this. The configurationcustomizers object comes from a traceable construction method, so it is container injected.

Creation of sqlsessiontemplate
@Bean
@ConditionalOnMissingBean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
  ExecutorType executorType = this.properties.getExecutorType();
  if (executorType != null) {
    return new SqlSessionTemplate(sqlSessionFactory, executorType);
  } else {
    return new SqlSessionTemplate(sqlSessionFactory);
  }
}

This method is very simple, that is, take the sqlsessionfactory just injected and create a new sqlsessiontemplate object based on it.

Mapperscannerregistrarnotfoundconfiguration class

Come to the last part of the file

/**
 * If mapper registering configuration or mapper scanning configuration not present, this configuration allow to scan
 * mappers based on the same component-scanning path as Spring Boot itself.
 */
@org.springframework.context.annotation.Configuration
@Import(AutoConfiguredMapperScannerRegistrar.class)
@ConditionalOnMissingBean({ MapperFactoryBean.class, MapperScannerConfigurer.class })
public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean {

  @Override
  public void afterPropertiesSet() {
    logger.debug(
        "Not found configuration for registering mapper bean using @MapperScan, MapperFactoryBean and MapperScannerConfigurer.");
  }

}

This is a static internal class. It only takes effect under the condition of @ conditionalonmissingbean ({mapperfactorybean. Class, mappercannerconfigurer. Class}), that is, it takes effect when there are no mapperfactorybean and mappercannerconfigurer beans in the container.

What works: @ import (autoconfiguratedmappercannerregister. Class): the @ import annotation is introduced again, and some beans are registered in the container. We can write the interface, add the @ mapper annotation, and then inject it into the mapper to access the database. All these operations are performed by autoconfiguredmappercannerregister This class is implemented for us.

AutoConfiguredMapperScannerRegistrar

[source code analysis] the principle of springboot automatic configuration and how mybatis is automatically configured

Since the importbeandefinitionregistar interface is implemented, we can see what is registered in the container by looking at the registerbeandefinitions method.

@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

  if (!AutoConfigurationPackages.has(this.beanFactory)) {
    logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.");
    return;
  }

  logger.debug("Searching for mappers annotated with @Mapper");

  List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
  if (logger.isDebugEnabled()) {
    packages.forEach(pkg -> logger.debug("Using auto-configuration base package '{}'", pkg));
  }

  BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
  builder.addPropertyValue("processPropertyPlaceHolders", true);
  builder.addPropertyValue("annotationClass", Mapper.class);
  builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(packages));
  BeanWrapper beanWrapper = new BeanWrapperImpl(MapperScannerConfigurer.class);
  Stream.of(beanWrapper.getPropertyDescriptors())
      // Need to mybatis-spring 2.0.2+
      .filter(x -> x.getName().equals("lazyInitialization")).findAny()
      .ifPresent(x -> builder.addPropertyValue("lazyInitialization", "${mybatis.lazy-initialization:false}"));
  registry.registerBeanDefinition(MapperScannerConfigurer.class.getName(), builder.getBeanDefinition());
}

Look directly at the last line

registry.registerBeanDefinition(MapperScannerConfigurer.class.getName(), builder.getBeanDefinition());

Nothing more than registering a mappercannerconfigurer. The previous code is setting the beandefinition, such as setting the annotationclass attribute to mapper Class for subsequent scanning. Basepackage attribute, which is the packages variable

You can see how the packages variable comes from

List<String> packages = AutoConfigurationPackages.get(this.beanFactory);

It was originally taken from the core container. Click this method

public static List<String> get(BeanFactory beanFactory) {
   try {
      return beanFactory. getBean(BEAN, BasePackages.class). get();// Take it from the container!!!
   }
   catch (NoSuchBeanDefinitionException ex) {
      throw new IllegalStateException("Unable to retrieve @EnableAutoConfiguration base packages");
   }
}

Isn’t this the bean registered with the @ autoconfigurationpackage annotation?

MapperScannerConfigurer

Finally, look at the class just registered

[source code analysis] the principle of springboot automatic configuration and how mybatis is automatically configured

It implements the beandefinitionregistrypostprocessor interface, which in turn implements the beanfactory postprocessor interface.

Supplement spring lifecycle

ApplicationContext will be loaded in the refresh () method, which is implemented by abstractapplicationcontext

[source code analysis] the principle of springboot automatic configuration and how mybatis is automatically configured

1. Subclasses do some processing for beanfactory

2.Initialize and call the beanfactoryprocessor object in the container

3.Initialize the beanpostprocessor object

4. Initialize message source

5. Initialize the application event multicast

6. Onrefresh () method is called. This method is also implemented by subclasses. For example, in servletwebserver ApplicationContext, the time of this method is to start the servlet container (typically Tomcat)

7. Register listeners

8. LoadingThe rest are not loadedofNon lazy loadingBean

9. Publish the event of refresh completion

From this life cycle, we see two special interfaces

Beanfactoryprocessor and its sub interfaces: in chaotic times,Modify beanfactory.A typical usage is to register a bean with it. For example, the configurationclasspostprocessor scans the @ component, @ import, @ bean and other annotations, and registers them all in the core container.

Beanpostprocessor and its sub interfaces:Called before and after each bean is created and initialized。 A typical example is the annotationawareaspectjautoproxycreator, which intervenes after each bean is initialized to proxy the bean to realize the AOP function.

In the current class at this stage
[source code analysis] the principle of springboot automatic configuration and how mybatis is automatically configured

The postprocessbeandefinitionregistry (beandefinitionregistry) method will be called to register a series of beans in the container!

So next we just need to know what it is registering for us.

@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.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
  if (StringUtils.hasText(lazyInitialization)) {
    scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
  }
  scanner.registerFilters();
  scanner.scan(
      StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}

It calls the scan method of the classpathmappercanner object to register the component with the container.

Core in
[source code analysis] the principle of springboot automatic configuration and how mybatis is automatically configured

Call firstDoscan of parent class

Then a post-processing is performed

processBeanDefinitions(beanDefinitions);

This method of the parent class scans the classes annotated by @ mapper in basepackages and returns a pile of bean definitions

[source code analysis] the principle of springboot automatic configuration and how mybatis is automatically configured

Here I wrote a mapper. The type of beandefinition is the interface type. In post-processing, change the type to org mybatis. spring. mapper. Mapperfactorybean type

private void processBeanDefinitions(Set<BeanDefinitionHolder> 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);// Changed the type!

    definition. getPropertyValues(). add("addToConfig", this.addToConfig);// set a property

    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);// Other complex attributes, go to the core container to get!!!!
    }
    definition.setLazyInit(lazyInitialization);
  }
}

Here are several key points 1 Changed the type of beandefinition 2 The constructor parameter of mapper interface type mapperfactorybean is set

3. Take other attributes of mapperfactorybean from the core container (such as the most important sqlsessionfactory and sqlsessiontemplate)

To sum up, we changed the beandefinition pointing to mapper interface class to point to mapperfactorybean class, and set some properties of this class (such as setting mapper interface class as the parameters of its construction method).

org.mybatis.spring.mapper.MapperFactoryBean

[source code analysis] the principle of springboot automatic configuration and how mybatis is automatically configured

This class implements the factorybean interface,

@Override
public T getObject();

The same principle as we used to write factory beans with configuration files.

That is to say, what is really in the container is the object returned by the GetObject method

This method is very simple

@Override
public T getObject() throws Exception {
  return getSqlSession().getMapper(this.mapperInterface);
}

This is the most familiar and classic use of mybatis. So we can inject @ Autowired into a mapper.

4. Summary

1. The @ enableautoconfiguration annotation reads all Classpaths: meta-inf / spring Factories, take the key as org springframework. boot. autoconfigure. All values under enableautoconfiguration are registered to the core container. The auto configuration class is loaded.

2. There are a large number of automatic configuration effective conditions on the automatic configuration class. Only when these conditions are met can the automatic configuration class be effective. Typically, dependency is not introduced.

3. Spring boot adopts the strategy of default instead of configuration. If it does not meet the requirements, you can easily change the default configuration. For example, modify

application. YML / properties file, manually register beans and register some classes that implement special interfaces.

4. The so-called automatic configuration is to register components with the container. Some components implement special interfaces, which affect the life cycle of spring.

5. Mybatis registered sqlsessionfactory and sqlsessiontemplate for us, and registered a mapper implementation class for each @ mapper.