Why use spring.factories for Spring Boot auto-configuration instead of annotations?

后端 未结 3 1738
感情败类
感情败类 2020-12-29 07:29

The documentation states:

Developing auto-configuration and using conditions

If you work in a company that develops shared libraries, or i

相关标签:
3条回答
  • 2020-12-29 07:54

    Because we are not going to scan the world to figure out what auto-configuration classes exist in your project. For one, an auto-configuration is just a regular @Configuration class.

    The way a Spring component is found is via explicit declaration or component scan but we need to know the list of auto-configuration classes way before we actually start the context.

    0 讨论(0)
  • 2020-12-29 08:07

    all the entries in spring.factories are loaded by below method -

    org.springframework.boot.autoconfigure.ImportAutoConfigurationImportSelector#loadFactoryNames

    protected Collection<String> loadFactoryNames(Class<?> source) {
            return SpringFactoriesLoader.loadFactoryNames(source, getClass().getClassLoader());
        }
    

    SpringFactoriesLoader belongs to the spring-core library see below screen shot

    0 讨论(0)
  • 2020-12-29 08:08

    When SpringBoot app is starting, it will not scan all the classes in jars, So SpringBoot starter should specify which classes are auto-configured. For example, in spring-boot-2.0.4.RELEASE, it initializes like this:

    @SpringBootApplication
    public class MyApplication {
        public static void main(String[] args) {
           //1. method run will call the construtor below
            SpringApplication.run(MyApplication.class, args);
        }
    }
    
        public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
            this.resourceLoader = resourceLoader;
            Assert.notNull(primarySources, "PrimarySources must not be null");
            this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
            this.webApplicationType = deduceWebApplicationType();
            //2. find all the classes whose key is ApplicationContextInitializer in spring.factories and initialize them 
            setInitializers((Collection) getSpringFactoriesInstances(
                    ApplicationContextInitializer.class));
            setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
            this.mainApplicationClass = deduceMainApplicationClass();
        }
    
    ...
        private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
                Class<?>[] parameterTypes, Object... args) {
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            // Use names and ensure unique to protect against duplicates
            Set<String> names = new LinkedHashSet<>(
                    //3. use current thread classcloader to load resources in the classpath
                    SpringFactoriesLoader.loadFactoryNames(type, classLoader));
            List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
                    classLoader, args, names);
            AnnotationAwareOrderComparator.sort(instances);
            return instances;
        }
    
    //SpringFactoriesLoader.java
    public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
            String factoryClassName = factoryClass.getName();
            // 3.1  first find the configuration file
            return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
        }
    
    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
            ...
            try {
                Enumeration<URL> urls = (classLoader != null ?
                //  public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; 
                //4. spring.factories file is defined here
                        classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                        ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
                result = new LinkedMultiValueMap<>();
                ...
        }
    
    0 讨论(0)
提交回复
热议问题