zoukankan      html  css  js  c++  java
  • Spring Boot的自动配置的原理

      Spring Boot在进行SpringApplication对象实例化时会加载META-INF/spring.factories文件,将该配置文件中的配置载入到Spring容器。

    1.1   Maven下载源码

    通过 dependency:sources 该命令可以下载该项目中所有的依赖的包的源码。

    1.2   源码分析

    org.springframework.boot.SpringApplication:

     

    org.springframework.core.io.support.SpringFactoriesLoader:

    由此可见,读取该配置文件来加载内容。

    1.3  Spring.factories文件

    # PropertySource Loaders
    org.springframework.boot.env.PropertySourceLoader=
    org.springframework.boot.env.PropertiesPropertySourceLoader,
    org.springframework.boot.env.YamlPropertySourceLoader
    
    # Run Listeners
    org.springframework.boot.SpringApplicationRunListener=
    org.springframework.boot.context.event.EventPublishingRunListener
    
    # Application Context Initializers
    org.springframework.context.ApplicationContextInitializer=
    org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,
    org.springframework.boot.context.ContextIdApplicationContextInitializer,
    org.springframework.boot.context.config.DelegatingApplicationContextInitializer,
    org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer
    
    # Application Listeners
    org.springframework.context.ApplicationListener=
    org.springframework.boot.ClearCachesApplicationListener,
    org.springframework.boot.builder.ParentContextCloserApplicationListener,
    org.springframework.boot.context.FileEncodingApplicationListener,
    org.springframework.boot.context.config.AnsiOutputApplicationListener,
    org.springframework.boot.context.config.ConfigFileApplicationListener,
    org.springframework.boot.context.config.DelegatingApplicationListener,
    org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,
    org.springframework.boot.logging.ClasspathLoggingApplicationListener,
    org.springframework.boot.logging.LoggingApplicationListener
    
    # Environment Post Processors
    org.springframework.boot.env.EnvironmentPostProcessor=
    org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,
    org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor
    
    # Failure Analyzers
    org.springframework.boot.diagnostics.FailureAnalyzer=
    org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,
    org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,
    org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,
    org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,
    org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,
    org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,
    org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer
    
    # FailureAnalysisReporters
    org.springframework.boot.diagnostics.FailureAnalysisReporter=
    org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter

     是代表没完的意思。

    1.4  举例:Redis的自动配置

    从上述的配置中可以看出,org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration是Redis的自动配置。

    内容:

     

    1.5   条件注解

     

    =============深入理解自动加载原理=============

      springboot依赖于maven的分模块开发。

    1.Spring Boot在进行SpringApplication对象实例化时会加载META-INF/spring.factories文件,将该配置文件中的配置载入到Spring容器。(自带的模块)

    我们引入下面这个包的时候:里面自带的   spring.factories  会初始化很多配置类,而且其jar包的自带的pom.xml引入了许多的jar包。然后扫描对应的XXXAutoConfiguration即可实现bean的注入。

    2.以mybatis自动配置为例如何配置默认没有的配置

     (1)引入mybatis-spring-boot-starter的jar包:

    目录结构如下:

    其pom.xml又引入了mybatis-spring-boot-autoconfigure的jar包,如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <!--
    
           Copyright 2015-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.
    
    -->
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <parent>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot</artifactId>
        <version>1.1.1</version>
      </parent>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <name>mybatis-spring-boot-starter</name>
      <dependencies>
        <dependency>
          <groupId>org.mybatis.spring.boot</groupId>
          <artifactId>mybatis-spring-boot-autoconfigure</artifactId>
          <version>1.1.1</version>
        </dependency>
      </dependencies>
    </project>

      (2)上面的依赖引入mybatis-spring-boot-autoconfigure的jar包,自动配置的主要设置在这个包中:

    •  先看这个包的pom文件

    pom.properties

    #Generated by Apache Maven
    #Mon Apr 18 20:21:18 EDT 2016
    version=1.1.1
    groupId=org.mybatis.spring.boot
    artifactId=mybatis-spring-boot-autoconfigure

    pom.xml(引入mybatis相关的依赖)

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot</artifactId>
            <version>1.1.1</version>
        </parent>
        <artifactId>mybatis-spring-boot-autoconfigure</artifactId>
        <name>mybatis-spring-boot-autoconfigure</name>
        
        <contributors>
            <contributor>
                <name>Josh Long</name>
                <email>josh@joshlong.com</email>
            </contributor>
            <contributor>
                <name>Kazuki Shimizu</name>
                <email>kazuki43zoo@gmail.com</email>
            </contributor>
        </contributors>
            
        <dependencies>
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>${mybatis.version}</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis-spring</artifactId>
                <version>${mybatis-spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-autoconfigure</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jdbc</artifactId>
            </dependency>
            <!-- @ConfigurationProperties annotation processing (metadata for IDEs) -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
                <optional>true</optional>
            </dependency>
            
            <!-- Test dependencies -->    
            <dependency>
                <groupId>com.h2database</groupId>
                <artifactId>h2</artifactId>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </project>
    •  再看spring.properties文件增加了MybatisAutoConfiguration,也就是启动时候会扫描这个类
    # Auto Configure
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=
    org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
    • 再看MybatisAutoConfiguration这个类的信息,相当于一个spring的xml配置文件,声明了一系列的bean,比如    SqlSessionFactory ,而且默认配置都在MybatisProperties类中声明
    /** <a href="http://www.cpupk.com/decompiler">Eclipse Class Decompiler</a> plugin, Copyright (c) 2017 Chen Chao. */
    package org.mybatis.spring.boot.autoconfigure;
    import java.util.List;
    
    import javax.annotation.PostConstruct;
    import javax.sql.DataSource;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.mapping.DatabaseIdProvider;
    import org.apache.ibatis.plugin.Interceptor;
    import org.apache.ibatis.session.ExecutorType;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.SqlSessionTemplate;
    import org.mybatis.spring.mapper.ClassPathMapperScanner;
    import org.mybatis.spring.mapper.MapperFactoryBean;
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.beans.factory.BeanFactoryAware;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.support.BeanDefinitionRegistry;
    import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
    import org.springframework.boot.autoconfigure.AutoConfigureAfter;
    import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
    import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.ResourceLoaderAware;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Import;
    import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
    import org.springframework.core.io.DefaultResourceLoader;
    import org.springframework.core.io.Resource;
    import org.springframework.core.io.ResourceLoader;
    import org.springframework.core.type.AnnotationMetadata;
    import org.springframework.util.Assert;
    import org.springframework.util.ObjectUtils;
    import org.springframework.util.StringUtils;
    
    @Configuration
    @ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
    @ConditionalOnBean(DataSource.class)
    @EnableConfigurationProperties(MybatisProperties.class)
    @AutoConfigureAfter(DataSourceAutoConfiguration.class)
    public class MybatisAutoConfiguration {
    
      private static Log log = LogFactory.getLog(MybatisAutoConfiguration.class);
    
      @Autowired
      private MybatisProperties properties;
    
      @Autowired(required = false)
      private Interceptor[] interceptors;
    
      @Autowired
      private ResourceLoader resourceLoader = new DefaultResourceLoader();
    
      @Autowired(required = false)
      private DatabaseIdProvider databaseIdProvider;
    
      @PostConstruct
      public void checkConfigFileExists() {
        if (this.properties.isCheckConfigLocation() && StringUtils.hasText(this.properties.getConfigLocation())) {
          Resource resource = this.resourceLoader.getResource(this.properties.getConfigLocation());
          Assert.state(resource.exists(), "Cannot find config location: " + resource
              + " (please add config file or check your Mybatis " + "configuration)");
        }
      }
    
      @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()));
        }
        factory.setConfiguration(properties.getConfiguration());
        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 (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
          factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
        }
        if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
          factory.setMapperLocations(this.properties.resolveMapperLocations());
        }
    
        return factory.getObject();
      }
    
      @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);
        }
      }
    
      public static class AutoConfiguredMapperScannerRegistrar
          implements BeanFactoryAware, ImportBeanDefinitionRegistrar, ResourceLoaderAware {
    
        private BeanFactory beanFactory;
    
        private ResourceLoader resourceLoader;
    
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    
          log.debug("Searching for mappers annotated with @Mapper'");
    
          ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
    
          try {
            if (this.resourceLoader != null) {
              scanner.setResourceLoader(this.resourceLoader);
            }
    
            List<String> pkgs = AutoConfigurationPackages.get(this.beanFactory);
            for (String pkg : pkgs) {
              log.debug("Using auto-configuration base package '" + pkg + "'");
            }
    
            scanner.setAnnotationClass(Mapper.class);
            scanner.registerFilters();
            scanner.doScan(StringUtils.toStringArray(pkgs));
          } catch (IllegalStateException ex) {
            log.debug("Could not determine auto-configuration " + "package, automatic mapper scanning disabled.");
          }
        }
    
        @Override
        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
          this.beanFactory = beanFactory;
        }
    
        @Override
        public void setResourceLoader(ResourceLoader resourceLoader) {
          this.resourceLoader = resourceLoader;
        }
      }
    
      @Configuration
      @Import({ AutoConfiguredMapperScannerRegistrar.class })
      @ConditionalOnMissingBean(MapperFactoryBean.class)
      public static class MapperScannerRegistrarNotFoundConfiguration {
    
        @PostConstruct
        public void afterPropertiesSet() {
          log.debug(String.format("No %s found.", MapperFactoryBean.class.getName()));
        }
      }
    
    }
    /** <a href="http://www.cpupk.com/decompiler">Eclipse Class Decompiler</a> plugin, Copyright (c) 2017 Chen Chao. */
    package org.mybatis.spring.boot.autoconfigure;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    import org.apache.ibatis.session.Configuration;
    import org.apache.ibatis.session.ExecutorType;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.core.io.Resource;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    
    /**
     * Configuration properties for Mybatis.
     *
     * @author Eddú Meléndez
     * @author Kazuki Shimizu
     */
    @ConfigurationProperties(prefix = MybatisProperties.MYBATIS_PREFIX)
    public class MybatisProperties {
    
      public static final String MYBATIS_PREFIX = "mybatis";
    
      /**
       * Config file path.
       */
      private String configLocation;
    
      /**
       * Location of mybatis mapper files.
       */
      private String[] mapperLocations;
    
      /**
       * Package to scan domain objects.
       */
      private String typeAliasesPackage;
    
      /**
       * Package to scan handlers.
       */
      private String typeHandlersPackage;
    
      /**
       * Check the config file exists.
       */
      private boolean checkConfigLocation = false;
    
      /**
       * Execution mode for {@link org.mybatis.spring.SqlSessionTemplate}.
       */
      private ExecutorType executorType;
    
      /**
       * A Configuration object for customize default settings. If {@link #configLocation}
       * is specified, this property is not used.
       */
      private Configuration configuration;
    
      /**
       * @since 1.1.0
       * @return
       */
      public String getConfigLocation() {
        return this.configLocation;
      }
    
      /**
       * @since 1.1.0
       * @return
       */
      public void setConfigLocation(String configLocation) {
        this.configLocation = configLocation;
      }
    
      @Deprecated
      public String getConfig() {
        return this.configLocation;
      }
    
      @Deprecated
      public void setConfig(String config) {
        this.configLocation = config;
      }
    
      public String[] getMapperLocations() {
        return this.mapperLocations;
      }
    
      public void setMapperLocations(String[] mapperLocations) {
        this.mapperLocations = mapperLocations;
      }
    
      public String getTypeHandlersPackage() {
        return this.typeHandlersPackage;
      }
    
      public void setTypeHandlersPackage(String typeHandlersPackage) {
        this.typeHandlersPackage = typeHandlersPackage;
      }
    
      public String getTypeAliasesPackage() {
        return this.typeAliasesPackage;
      }
    
      public void setTypeAliasesPackage(String typeAliasesPackage) {
        this.typeAliasesPackage = typeAliasesPackage;
      }
    
      public boolean isCheckConfigLocation() {
        return this.checkConfigLocation;
      }
    
      public void setCheckConfigLocation(boolean checkConfigLocation) {
        this.checkConfigLocation = checkConfigLocation;
      }
    
      public ExecutorType getExecutorType() {
        return this.executorType;
      }
    
      public void setExecutorType(ExecutorType executorType) {
        this.executorType = executorType;
      }
    
      public Configuration getConfiguration() {
        return configuration;
      }
    
      public void setConfiguration(Configuration configuration) {
        this.configuration = configuration;
      }
    
      public Resource[] resolveMapperLocations() {
        List<Resource> resources = new ArrayList<Resource>();
        if (this.mapperLocations != null) {
          for (String mapperLocation : this.mapperLocations) {
            Resource[] mappers;
            try {
              mappers = new PathMatchingResourcePatternResolver().getResources(mapperLocation);
              resources.addAll(Arrays.asList(mappers));
            } catch (IOException e) {
    
            }
          }
        }
    
        Resource[] mapperLocations = new Resource[resources.size()];
        mapperLocations = resources.toArray(mapperLocations);
        return mapperLocations;
      }
    }

      这个文件也决定了我们在application.properties文件中配置mybatis的格式如下:

    ############################################################
    #
    # Mybatis settings
    #
    ############################################################
    #jiazai mybatis peizhiwenjian(**代表任意目录,*代表任意多个字符)
    mybatis.mapper-locations = classpath:mapper/**/*Mapper.xml
    mybatis.config-location = classpath:mybatis/SqlMapConfig.xml
    mybatis.type-aliases-package = cn.qlq.bean

      这个也就是自动配置的大致过程。如果我们想自己写一个这样的自动配置,可以按照这个逆向去写就可以了。

  • 相关阅读:
    JAVA对象之生
    单表扫描,MySQL索引选择不正确 并 详细解析OPTIMIZER_TRACE格式
    [MySQL 5.6] 初识5.6的optimizer trace
    [MySQL5.6] 一个简单的optimizer_trace示例
    PERFORMANCE_SCHEMA 详解
    MetaData Lock 杨奇龙 ---MYSQL博客专家
    ArcEngine控制台应用程序
    一位数据科学家的私房工具清单
    数据可视化之热力图
    数据可视化之MarkPoint
  • 原文地址:https://www.cnblogs.com/qlqwjy/p/8446237.html
Copyright © 2011-2022 走看看