• Spring Boot自动配置原理


    Spring Boot的自动配置注解是@EnableAutoConfiguration, 从上面的@Import的类可以找到下面自动加载自动配置的映射。

    /**
         * Load the fully qualified class names of factory implementations of the
         * given type from {@value #FACTORIES_RESOURCE_LOCATION}, using the given
         * class loader.
         * @param factoryClass the interface or abstract class representing the factory
         * @param classLoader the ClassLoader to use for loading resources; can be
         * {@code null} to use the default
         * @throws IllegalArgumentException if an error occurs while loading factory names
         * @see #loadFactories
         */
        public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
            String factoryClassName = factoryClass.getName();
            return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
        }
    
        private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
            MultiValueMap<String, String> result = cache.get(classLoader);
            if (result != null) {
                return result;
            }
    
            try {
                Enumeration<URL> urls = (classLoader != null ?
                        classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                        ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
                result = new LinkedMultiValueMap<>();
                while (urls.hasMoreElements()) {
                    URL url = urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    for (Map.Entry<?, ?> entry : properties.entrySet()) {
                        String factoryClassName = ((String) entry.getKey()).trim();
                        for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
                            result.add(factoryClassName, factoryName.trim());
                        }
                    }
                }
                cache.put(classLoader, result);
                return result;
            }
            catch (IOException ex) {
                throw new IllegalArgumentException("Unable to load factories from location [" +
                        FACTORIES_RESOURCE_LOCATION + "]", ex);
            }
        }

    这个方法会加载类路径及所有jar包下META-INF/spring.factories配置中映射的自动配置的类。

    /**
         * The location to look for factories.
         * <p>Can be present in multiple JAR files.
         */
        public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

    查看Spring Boot自带的自动配置的包: spring-boot-autoconfigure-1.5.6.RELEASE.jar,打开其中的META-INF/spring.factories文件会找到自动配置的映射。

    # Auto Configure
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=
    org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,
    org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,
    org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,
    org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,
    org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,
    org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,
    org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,
    ...

    我们看看数据源自动配置的实现注解

    @Configuration
    @ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
    @EnableConfigurationProperties(DataSourceProperties.class)
    @Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
    public class DataSourceAutoConfiguration {
    ...

    @Configuration,@ConditionalOnClass就是自动配置的核心,首先它得是一个配置文件,其次根据类路径下是否有这个类去自动配置。

    创建一个自定义Starter

    这个自定义 Starter 就实现一个根据属性的值是否配置Bean。

    1、创建自动配置类

    import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @ConditionalOnProperty(prefix = "com.hzy.starter", name = "enabled", havingValue = "true")
    public class TestServiceAutoConfiguration {
    
        @Bean
        public TestService testService() {
            return new TestService();
        }
    
    }

    这个自动配置类很简单,就是根据是否有 com.hzy.starter.enabled=true这个参数的值再配置一个Bean

    TestService示例如下:

    public class TestService {
    
        public String getServiceName() {
            return "com.hzy.starter";
        }
    
    }

    2、允许自动配置

    创建 META-INF/spring.factories 文件,添加这个允许自动配置的类。

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=
    com.hzy.springboot.starter.config.TestServiceAutoConfiguration

    3、测试这个自定义Starter

    import org.springframework.boot.CommandLineRunner;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.Bean;
    
    
    @SpringBootApplication
    public class Application {
    
        public static void main(String[] args) {
            SpringApplication.run(Application.class);
        }
    
        @Bean
        public CommandLineRunner commandLineRunner(TestService testService) {
            return (args) -> {
                System.out.println(testService.getServiceName());
            };
        }
    
    }

    4、开启配置

    我们知道这个自定义 Starter 中需要有 com.hzy.starter.enabled=true 这个参数的值的,所以我们在 application.xml 配置文件中添加这个配置:

    com.hzy.starter.enabled=true
    

    5、运行测试

    运行 Application 类的 main 方法,最后会输出结果:com.hzy.starter。

  • 相关阅读:
    P/Invoke .NET调用win32API
    怎么将字节流转换成汉字?(硬件printf的汉字怎么解析?)
    个人电脑配置FTP服务器,四张图搞定。项目需要,并自己写了个客户端实现下载和上传的功能!
    C# 中Datetime类用法总结
    C#环境datagidview添加删除操作
    C#环境下,文本框翻屏,怎么一直显示当前插入的内容!!!!!!!!!!!!!!!!
    eclipse下提交job时报错mapred.JobClient: No job jar file set. User classes may not be found.
    SQL Server连接数据库失败,可能的问题!
    写好的mapreduce程序,编译,打包,得到最后的jar包! 验证jar包 ! 整体流程
    在虚拟机环境下,电脑间拷贝配置好的伪分布式Hadoop环境,出现namenode不能启动的问题!
  • 原文地址:https://www.cnblogs.com/Joy-Hu/p/12163583.html
Copyright © 2020-2023  润新知