zoukankan      html  css  js  c++  java
  • SpringBoot自动配置原理

    1)、SpringBoot启动的时候加载主配置类,开启了自动配置功能 @EnableAutoConfiguration

    2)、@EnableAutoConfiguration 作用:

    SpringFactoriesLoader.loadFactoryNames()
    扫描所有jar包类路径下 META‐INF/spring.factories
    把扫描到的这些文件的内容包装成properties对象
    从properties中获取到EnableAutoConfiguration.class类(类名)对应的值,然后把他们添加在容器中

     将 类路径下 META-INF/spring.factories 里面配置的所有EnableAutoConfiguration的值加入到了容器中;

    E:DevelopToolsapache-maven-3.6.0
    epsitoryorgmybatisspringootmybatis-spring-boot-autoconfigure2.0.1mybatis-spring-boot-autoconfigure-2.0.1.jar!META-INFspring.factories
    
    # Auto Configure
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=
    org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

    每一个这样的 xxxAutoConfiguration类都是容器中的一个组件,都加入到容器中;用他们来做自动配置;
    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    package org.mybatis.spring.boot.autoconfigure;
    
    import java.util.Iterator;
    import java.util.List;
    import java.util.function.Consumer;
    import javax.sql.DataSource;
    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.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.beans.factory.BeanFactoryAware;
    import org.springframework.beans.factory.InitializingBean;
    import org.springframework.beans.factory.ObjectProvider;
    import org.springframework.beans.factory.support.BeanDefinitionRegistry;
    import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
    import org.springframework.boot.autoconfigure.AutoConfigureAfter;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
    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.Resource;
    import org.springframework.core.io.ResourceLoader;
    import org.springframework.core.type.AnnotationMetadata;
    import org.springframework.util.Assert;
    import org.springframework.util.CollectionUtils;
    import org.springframework.util.ObjectUtils;
    import org.springframework.util.StringUtils;
    
    @Configuration
    @ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
    @ConditionalOnSingleCandidate(DataSource.class)
    @EnableConfigurationProperties({MybatisProperties.class})
    @AutoConfigureAfter({DataSourceAutoConfiguration.class})
    public class MybatisAutoConfiguration implements InitializingBean {
        private static final Logger logger = LoggerFactory.getLogger(MybatisAutoConfiguration.class);
        private final MybatisProperties properties;
        private final Interceptor[] interceptors;
        private final ResourceLoader resourceLoader;
        private final DatabaseIdProvider databaseIdProvider;
        private final List<ConfigurationCustomizer> configurationCustomizers;
    
        public MybatisAutoConfiguration(MybatisProperties properties, ObjectProvider<Interceptor[]> interceptorsProvider, ResourceLoader resourceLoader, ObjectProvider<DatabaseIdProvider> databaseIdProvider, ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider) {
            this.properties = properties;
            this.interceptors = (Interceptor[])interceptorsProvider.getIfAvailable();
            this.resourceLoader = resourceLoader;
            this.databaseIdProvider = (DatabaseIdProvider)databaseIdProvider.getIfAvailable();
            this.configurationCustomizers = (List)configurationCustomizersProvider.getIfAvailable();
        }
    
        public void afterPropertiesSet() {
            this.checkConfigFileExists();
        }
    
        private 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()));
            }
    
            this.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.properties.resolveMapperLocations())) {
                factory.setMapperLocations(this.properties.resolveMapperLocations());
            }
    
            return factory.getObject();
        }
    
        private void applyConfiguration(SqlSessionFactoryBean factory) {
            org.apache.ibatis.session.Configuration configuration = this.properties.getConfiguration();
            if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) {
                configuration = new org.apache.ibatis.session.Configuration();
            }
    
            if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) {
                Iterator var3 = this.configurationCustomizers.iterator();
    
                while(var3.hasNext()) {
                    ConfigurationCustomizer customizer = (ConfigurationCustomizer)var3.next();
                    customizer.customize(configuration);
                }
            }
    
            factory.setConfiguration(configuration);
        }
    
        @Bean
        @ConditionalOnMissingBean
        public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
            ExecutorType executorType = this.properties.getExecutorType();
            return executorType != null ? new SqlSessionTemplate(sqlSessionFactory, executorType) : new SqlSessionTemplate(sqlSessionFactory);
        }
    
        @Configuration
        @Import({MybatisAutoConfiguration.AutoConfiguredMapperScannerRegistrar.class})
        @ConditionalOnMissingBean({MapperFactoryBean.class})
        public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean {
            public MapperScannerRegistrarNotFoundConfiguration() {
            }
    
            public void afterPropertiesSet() {
                MybatisAutoConfiguration.logger.debug("No {} found.", MapperFactoryBean.class.getName());
            }
        }
    
        public static class AutoConfiguredMapperScannerRegistrar implements BeanFactoryAware, ImportBeanDefinitionRegistrar, ResourceLoaderAware {
            private BeanFactory beanFactory;
            private ResourceLoader resourceLoader;
    
            public AutoConfiguredMapperScannerRegistrar() {
            }
    
            public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
                if (!AutoConfigurationPackages.has(this.beanFactory)) {
                    MybatisAutoConfiguration.logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.");
                } else {
                    MybatisAutoConfiguration.logger.debug("Searching for mappers annotated with @Mapper");
                    List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
                    if (MybatisAutoConfiguration.logger.isDebugEnabled()) {
                        packages.forEach((pkg) -> {
                            MybatisAutoConfiguration.logger.debug("Using auto-configuration base package '{}'", pkg);
                        });
                    }
    
                    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
                    if (this.resourceLoader != null) {
                        scanner.setResourceLoader(this.resourceLoader);
                    }
    
                    scanner.setAnnotationClass(Mapper.class);
                    scanner.registerFilters();
                    scanner.doScan(StringUtils.toStringArray(packages));
                }
            }
    
            public void setBeanFactory(BeanFactory beanFactory) {
                this.beanFactory = beanFactory;
            }
    
            public void setResourceLoader(ResourceLoader resourceLoader) {
                this.resourceLoader = resourceLoader;
            }
        }
    }
    View Code
    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    package org.mybatis.spring.boot.autoconfigure;
    
    import java.io.IOException;
    import java.util.Optional;
    import java.util.Properties;
    import java.util.function.Function;
    import java.util.function.IntFunction;
    import java.util.stream.Stream;
    import org.apache.ibatis.session.Configuration;
    import org.apache.ibatis.session.ExecutorType;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.boot.context.properties.NestedConfigurationProperty;
    import org.springframework.core.io.Resource;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    import org.springframework.core.io.support.ResourcePatternResolver;
    
    @ConfigurationProperties(
        prefix = "mybatis"
    )
    public class MybatisProperties {
        public static final String MYBATIS_PREFIX = "mybatis";
        private static final ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
        private String configLocation;
        private String[] mapperLocations;
        private String typeAliasesPackage;
        private Class<?> typeAliasesSuperType;
        private String typeHandlersPackage;
        private boolean checkConfigLocation = false;
        private ExecutorType executorType;
        private Properties configurationProperties;
        @NestedConfigurationProperty
        private Configuration configuration;
    
        public MybatisProperties() {
        }
    
        public String getConfigLocation() {
            return this.configLocation;
        }
    
        public void setConfigLocation(String configLocation) {
            this.configLocation = configLocation;
        }
    
        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 Class<?> getTypeAliasesSuperType() {
            return this.typeAliasesSuperType;
        }
    
        public void setTypeAliasesSuperType(Class<?> typeAliasesSuperType) {
            this.typeAliasesSuperType = typeAliasesSuperType;
        }
    
        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 Properties getConfigurationProperties() {
            return this.configurationProperties;
        }
    
        public void setConfigurationProperties(Properties configurationProperties) {
            this.configurationProperties = configurationProperties;
        }
    
        public Configuration getConfiguration() {
            return this.configuration;
        }
    
        public void setConfiguration(Configuration configuration) {
            this.configuration = configuration;
        }
    
        public Resource[] resolveMapperLocations() {
            return (Resource[])Stream.of((Object[])Optional.ofNullable(this.mapperLocations).orElse(new String[0])).flatMap((location) -> {
                return Stream.of(this.getResources(location));
            }).toArray((x$0) -> {
                return new Resource[x$0];
            });
        }
    
        private Resource[] getResources(String location) {
            try {
                return resourceResolver.getResources(location);
            } catch (IOException var3) {
                return new Resource[0];
            }
        }
    }
    View Code

    3)、每一个自动配置类进行自动配置功能;

    4)、以HttpEncodingAutoConfiguration(Http编码自动配置)为例解释自动配置原理;

    @Configuration //表示这是一个配置类,以前编写的配置文件一样,也可以给容器中添加组件
    @EnableConfigurationProperties(HttpEncodingProperties.class) //启动指定类的
    ConfigurationProperties功能;将配置文件中对应的值和HttpEncodingProperties绑定起来;并把
    HttpEncodingProperties加入到ioc容器中
    @ConditionalOnWebApplication //Spring底层@Conditional注解(Spring注解版),根据不同的条件,如果
    满足指定的条件,整个配置类里面的配置就会生效; 判断当前应用是否是web应用,如果是,当前配置类生效
    @ConditionalOnClass(CharacterEncodingFilter.class) //判断当前项目有没有这个类
    CharacterEncodingFilter;SpringMVC中进行乱码解决的过滤器;
    @ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing =
    true) //判断配置文件中是否存在某个配置 spring.http.encoding.enabled;如果不存在,判断也是成立的
    //即使我们配置文件中不配置pring.http.encoding.enabled=true,也是默认生效的;
    public class HttpEncodingAutoConfiguration {
    //他已经和SpringBoot的配置文件映射了
    private final HttpEncodingProperties properties;
    //只有一个有参构造器的情况下,参数的值就会从容器中拿
    public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
    this.properties = properties;
    }
    @Bean //给容器中添加一个组件,这个组件的某些值需要从properties中获取
    @ConditionalOnMissingBean(CharacterEncodingFilter.class) //判断容器没有这个组件?
    public CharacterEncodingFilter characterEncodingFilter() {
    CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
    filter.setEncoding(this.properties.getCharset().name());
    filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
    filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
    return filter;
    }

    5)、所有在配置文件中能配置的属性都是在xxxxProperties类中封装者‘;配置文件能配置什么就可以参照某个功能对应的这个属性类

    @ConfigurationProperties(prefix = "spring.http.encoding") //从配置文件中获取指定的值和bean的属
    性进行绑定
    public class HttpEncodingProperties {
    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF‐8");

    精髓:
    1)、SpringBoot启动会加载大量的自动配置类
    2)、我们看我们需要的功能有没有SpringBoot默认写好的自动配置类;
    3)、我们再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件有,我们就不需要再来配置了)
    4)、给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们就可以在配置文件中指定这
    些属性的值;
    xxxxAutoConfigurartion:自动配置类;
    给容器中添加组件

    xxxxProperties:封装配置文件中相关属性;

  • 相关阅读:
    单例模式
    HashSet、LinkedHashSet、SortedSet、TreeSet
    ArrayList、LinkedList、CopyOnWriteArrayList
    HashMap、Hashtable、LinkedHashMap
    andrew ng machine learning week8 非监督学习
    andrew ng machine learning week7 支持向量机
    andrew ng machine learning week6 机器学习算法理论
    andrew ng machine learning week5 神经网络
    andrew ng machine learning week4 神经网络
    vue组件监听属性变化watch方法报[Vue warn]: Method "watch" has type "object" in the component definition. Did you reference the function correctly?
  • 原文地址:https://www.cnblogs.com/ustc-anmin/p/11267089.html
Copyright © 2011-2022 走看看